Java线程生命周期模型
状态 | 说明 |
---|---|
NEW | 初始状态,构建完成的线程,并未调用start()方法,仅仅被new出来而已 |
RUNABLE | 运行状态,java线程中把准备就绪和正在运行的状态统一称为运行中,即RUNABLE,表示可以运行的状态 |
BLOCKED | 阻塞状态,此时线程被锁阻塞,并未执行 |
WAITING | 等待状态,表示线程进入等待状态,持续等待直到该线程所等待的线程执行完毕或中断,或是接收到通知运行的通知,即其他线程使用notify()或notifyAll()方法 |
TIMED_WAITING | 超时等待状态,没有耐心的线程,等待指定的时间后自行返回,停止等待 |
TERMINATED | 终止状态,表示线程已执行完毕 |
各生命周期的转化方法
从无到NEW(实例化) | Thread thread = new Thread(yourThread); |
---|---|
NEW->RUNABLE | Thread.start() |
RUNABLE->BLOCKED | 等待进入synchronized方法/块 |
BLOCKED->RUNABLE | 获取到该synchronized方法/块的锁 |
RUNABLE->WAITING | Object.wait(),Thread.jion(),LockSupport.park() |
RUNABLE->TIMED_WAITING | Object.wait(long),Thread.jion(long),Thread.sleep(long),LockSupport.parkNanos(),LockSupport.parkUntil() |
WAITING/TIMED_WAITING->RUNABLE | Object.notify(),Object.notifyAll(),LockSupport.unpark(Thread) |
RUNABLE->TERMINATED | 执行完毕即终止运行 |
各生命周期详解
NEW - 创建线程
运行线程前首先要构造一个线程对象出来,创建线程一般有三种方式
1.继承Thread类并重写run方法
public class MyThread extends Thread{
@override
void run(){
//......
}
}
2.实现Runable接口
public class MyThread implements Runnable{
public void run(){
//......
}
}
3.实现Callable和Future接口
public class MyThread implements Callable{
public Object call(){
//remember return something
return "whatever you want";
}
}
三种方法的优劣
方法 | 优势 | 劣势 |
---|---|---|
继承Thread类并重写run方法 | 编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。 | 已经继承了Thread作为父类,不能继承其他父类 |
实现Runable,Callable和Future接口 | 线程只是实现了接口,还可以继承其他类,避免了Java不能多重继承的限制 | 编程复杂度较高,如果要访问当前线程,则必须使用Thread.currentThread()方法。 |
构造完线程对象后,此时还并未调用start()方法,可以在此时对线程进行设置,诸如:
优先级,父线程,是否为后台线程,所属线程组,线程池等。
RUNABLE - 运行线程
对已经实例化的Thread对象调用start()方法,即可让其进入RUNABLE状态。start()的具体语义是:当前线程同步告知jvm,只要线程规划器空闲,应立即启动调用start()的线程。
BLOCKED - 线程阻塞
java线程的阻塞与I/O的阻塞是不同的,BLOCKED(阻塞状态)特指进入同步方法、块时的阻塞。
更加详细的定义可以参考 Thread.State 中的 javadoc:
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
此处翻译来源:Java 线程状态之 BLOCKED
这句话很长,可以拆成两个简单句来理解。
-
A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method。
一个处于 blocked 状态的线程正在等待一个监视器锁以进入一个同步的块或方法。
-
A thread in the blocked state is waiting for a monitor lock to reenter a synchronized block/method after calling Object.wait。
一个处于 blocked 状态的线程正在等待一个监视器锁,在其调用 Object.wait 方法之后,以再次进入一个同步的块或方法。
通过上述翻译,我们可以知道,阻塞将会发生在:
1.当前线程进入同步方法、块时,等待锁的获取
2.重新进入当前同步块时,等待锁的获取
其中详细解释一下2。如果同步方法、块中,调用了Object.wait方法,则当前线程会释放所占用的锁,在其wait结束后,则需要重新获取该同步方法、块的锁,所以在获取不到锁时,将会使该线程阻塞。
WAITING及TIMED_WAITING - 等待状态
要进入WAITING或TIMED_WAITING的状态,需要该线程在RUNABLE时调用Object.wait,Thread.join,LockSupport.park等方法。对于WAITING及TIMED_WAITING状态,WAITING状态详细的语义为,该线程目前在等待进一步指示,主动进行暂停。
想要通知WAITING及TIMED_WAITING状态的线程返回RUNABLE,则需要使用**Object.notify(),Object.notifyAll(),LockSupport.unpark(Thread)**等方法。
值得注意的是,wait()方法会使当前线程释放所持有的锁。所以上文提到的WAITING状态结束,被使用上述函数唤醒后,如果要运行或运行在同步方法、块,则需要重新参与锁的竞争,故线程有可能从WAITING及TIMED_WAITING状态在进入RUNABLE状态后瞬间被堵塞变为BLOCKED状态,即使线程是从同步方法、块中被唤醒,也会被堵塞。
TERMINATED - 终止状态
当线程运行完毕,则进入终止状态,如果线程在阻塞时被使用Thread.interrupt()中断,也会进入终止状态。要注意,原本用于终止线程的stop()方法已经过时,原因是这个方法会导致所占用资源的释放出现异常,可能会产生死锁现象。