多线程的实现方法
Java 中实现多线程有两种方法:继承 Thread 类、实现 Runnable 接口
使用 interrupt()中断线程
当对一个线程调用 interrupt 方法时,线程的中断状态将被置位。这是每一个线程都具有
的 boolean 标志。每个线程都应该不时地检査这个标志, 以判断线程是否被中断。
package com.ping;
import java.util.logging.Logger;
/**
* @author zwp
* @version 1.00 2018/8/22.
*/
public class SleepInterrupt extends Object implements Runnable{
public void run(){
while (!Thread.currentThread().isInterrupted())
{
System.out.println("Interrupted状态:"+Thread.currentThread().isInterrupted());
}
if (Thread.currentThread().isInterrupted()) {
System.out.println("Interrupted状态:"+Thread.currentThread().isInterrupted());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//sleep遇到Interrupted状态为true会抛出InterruptedException异常
e.printStackTrace();
System.out.println("抛出异常后Interrupted状态:"+Thread.currentThread().isInterrupted());
}
}
System.out.println("in run() - 线程运行完毕");
}
public static void main(String[] args) throws InterruptedException {
SleepInterrupt si = new SleepInterrupt();
Thread t = new Thread(si);
t.start();
//主线程休眠,从而确保刚才启动的线程有机会执行一段时间
try {
Thread.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("in main() - 对t线程使用interrupt()");
//中断线程t
t.interrupt();
System.out.println("in main() - 对t线程使用interrupt() OK");
Thread.sleep(2000);
System.out.println("in main() - 主线程完毕");
}
}
使用 isInterrupted()方法判断中断状态
可以在 Thread 对象上调用 isInterrupted()方法来检查任何线程的中断状态。这里需要注意:线程一旦被中断,isInterrupted()方法便会返回 true,而一旦 sleep()方法抛出异常,它将清空中断标志,此时isInterrupted()方法将返回 false。
使用 Thread.interrupted()方法判断中断状态
测试当前线程(即正在执行这一命令的线程)是否被中断。注意,这是一个静态方法。这一调用会产生副作用 —— 它将当前线程的中断状态重置为 false。
线程状态
线程状态可以有以下6种:
1. New (新创建)
2. Runnable (可运行)
3. Blocked (被阻塞)
4. Waiting (等待)
5. Timed waiting (计时等待)
6. Terminated (被终止)
要确定一个线程的当前状态, 可调用 getState 方法。
新创建线程:当用 new 操作符创建一个新线程时,如 newThread(r), 该线程还没有开始运行。
可运行线程:一个可运行的线程可能正在运行也可能没有运行, 这取决于操作系统给线程提供运行的时间。
被阻塞线程和等待线程:当线程处于被阻塞或等待状态时,它暂时不活动。它不运行任何代码且消耗最少的资
源。直到线程调度器重新激活它。
- 当一个线程试图获取一个内部的对象锁(而不是 javiutiUoncurrent 库中的锁,) 而该锁被其他线程持有, 则该线程进人阻塞状态。
- 当所有其他线程释放该锁,并且线程调度器允许本线程持有它的时候,该线程将变成非阻塞状态。
- 当线程等待另一个线程通知调度器一个条件时,它自己进入等待状态。在调用 Object.wait 方法或 Thread.join 方法, 或者是等待 java,util.concurrent 库中的 Lock 或 Condition 时,
就会出现这种情况。实际上,被阻塞状态与等待状态是有很大不同的。- 有几个方法有一个超时参数。调用它们导致线程进人计时等待( timed waiting ) 状态。这一状态将一直保持到超时期满或者接收到适当的通知。带有超时参数的方法有Thread.sleep 和
Object.wait、Thread.join、 Lock,tryLock 以及 Condition.await 的计时版。
被终止的线程:因为 run 方法正常退出而自然死亡。因为一个没有捕获的异常终止了 nm 方法而意外死亡。可以调用线程的 stop 方法杀死一个线程,该方法抛出 ThreadDeath 错误对象,由此杀死线程。
- void stop() 停止该线程。这一方法已过时。
- void suspend() 暂停这一线程的执行。这一方法已过时。
- void resume() 恢复线程。这一方法仅仅在调用 suspendO 之后调用。这一方法已过时。
线程优先级
在 Java 程序设计语言中,每一个线程有一个优先级。默认情况下, 线程继承它的父
线程的优先级。
每当线程调度器有机会选择新线程时, 它首先选择具有较高优先级的线程。但是,线程
优先级是高度依赖于系统的。
void setPriority(int newPriority) 设置线程的优先级。
static int MIN_PRIORITY 线程的最小优先级。最小优先级的值为 1。
static int N0RM_PRI0RITY 线程的默认优先级。默认优先级为 5。
static int MAX_PRIORITY 线程的最高优先级。最高优先级的值为 10。
static void yield( ) 导致当前执行线程处于让步状态。如果有其他的可运行线程具有至少与此线程同样高的优先级,那么这些线程接下来会被调度。注意,这是一个静态方法
守护线程
Java 中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)。
setDaemon(true)方法设置当前线程为守护线程。
虽然守护线程可能非常有用,但必须小心确保其他所有非守护线程消亡时,不会由于它的终止而产生任何危害。因为你不可能知道在所有的用户线程退出运行前,守护线程是否已经完成了预期的服务任务。一旦所有的用户线程退出了,虚拟机也就退出运行了。
- setDaemon(true)必须在调用线程的 start()方法之前设置,否则会跑出IllegalThreadStateException 异常。
- 在守护线程中产生的新线程也是守护线程。
线程阻塞
线程可以阻塞于四种状态:
- 当线程执行 Thread.sleep()时,它一直阻塞到指定的毫秒时间之后,或者阻塞被另一个线程打断;
- 当线程碰到一条 wait()语句时,它会一直阻塞到接到通知(notify())、被中断或经过了指定毫秒时间为止(若制定了超时值的话)
- 线程阻塞与不同 I/O 的方式有多种。常见的一种方式是
InputStream的read()方法,该方法一直阻塞到从流中读取一个字节的数据为止,它可以无限阻塞,因此不能指定超时时间; - 线程也可以阻塞等待获取某个对象锁的排他性访问权限(即等待获得 synchronized 语句必须的锁时阻塞)。