线程状态转换
1.新建
创建后尚未启动即new了一个线程。
2.运行
处于运行状态,也可能正在等待cpu的时间片,包含了操作系统的线程的running状态和ready状态。
3.阻塞
等待获取一个排它锁,如果其他线程释放了锁就会结束这种状态。
4.无限期等待
等待其他线程的显示唤醒,否则不会被分配cpu时间片。
进入方法 | 退出方法 |
---|---|
没有设置Timeout的Object.wait()方法 | Object.notify()或者Object.notifyAll(); |
没有设置Timeout的Thread.join()方法 | 等到被调用的线程执行完毕 |
LockSupport.park() | LockSupport.unpark(Thread) |
LockSupport是JDK中比较底层的类,用来创建锁和其他同步工具类的基本线程阻塞元语。java锁的同步框架的核心AQS:AbstractQueuedSychronizer,就是调用LockSupport.park(),和LockSupport.unpark()实现线程的阻塞和唤醒。LockSupport很类似于二元信号量(只有一个许可证可以使用),如果这个许可证还没被占用,当前线程获取许可证并继续执行;如果许可证已经被占用,当前线程阻塞,等待获取许可。
public static void main(String[]args){
LockSupport.park();
System.out.println("block");
}
运行该代码,主线程会一直处于阻塞状态,原因是许可证默认是被占用的,调用park()时,获取不到许可证,所以进入阻塞状态。
如下代码:先释放掉许可证,在获取许可,主线程能正常的终止。
public static void main(String[]args){
Thread thread=Thread.currentThread();
LockSupport.unpark(thread);//释放许可
LockSupport.park(); //获取许可
System.out.println("b");
}
LockSuppot是不可重入的,并且LockSupport能够在阻塞状态下响应中断。
5.限期等待
无需其他线程显示的唤醒,在一定的时间后会被系统自动唤醒。
调用Thread.sleep()方法使线程进入限期等待状态,常常用一个线程进入睡眠状态来描述。
调用Object.wait()方法使线程进入限期等待或者无限期等待,常用挂起一个线程来描述。
睡眠和挂起是用来描述行为,而等待和阻塞是用来描述状态。
阻塞和等待的区别是,阻塞是被动的,它在等待一个排它锁。而等待是主动的,通过调用Thread.sleep()和Object.wait()进入。
进入方法 | 退出方法 |
---|---|
Thread.sleep()方法 | 时间结束 |
设置了Timeout的Object.wait()方法 | 时间结束/notify()/notifyAll() |
设置了Timeout的Object.join()方法 | 时间结束/被调用的线程执行完毕 |
LockSupport.parkNanos()方法 | LockSupport.unpark(Thread) |
LockSupport.parkUntil()方法 | LockSuppoort.unpark(Thread) |
LockSupport.parkNanos()阻塞当前进程,最长时间不超过nanos秒,返回条件在park()的基础上增加了超时返回。
LockSupport.parkUntil(),阻塞当前线程,知道deadline时间。
6.死亡
可能是线程结束任务后的正常死亡,也可能是产生了异常而结束。