Java并发知识体系持续更新:https://blog.csdn.net/m0_46144826/category_9881831.html
操作系统层面,线程有以下状态:
这五种状态是最基本的转换模型。在不同的编程语言中,会有细微区别。
对 Java
来说,线程状态已经确定在了 Thread 内部类的枚举中:
public enum State {
NEW,//尚未启动的线程的线程状态
RUNNABLE,//可运行线程的线程状态。处于可运行状态的线程正在Java虚拟机中执行,但可能正在等待来自操作系统的其他资源,例如处理器。
BLOCKED,//阻塞状态
WAITING,//等待线程的线程状态
TIMED_WAITING,//具有指定等待时间的等待线程的线程状态
TERMINATED;//终止线程的线程状态。线程已完成执行。
}
Blocking、 Waiting、Timed Waiting 其实都是休眠状态,在 Java 中进行了区分。
可运行状态和运行状态合并成 Runnable。
然后看看详细介绍
线程对象被创建时,它只会短暂地处于这种状态。此时它已经分配了必须的系统资源,并执行了初始化。
相当于,这个线程还没有调用 start()
方法。
Runnable
状态包括了操作系统线程状态中的 Running 和 Ready,也就是处于此状态的线程可能正在运行,也可能正在等待系统资源,如等待 CPU 为它分配时间片,如等待网络IO读取数据。
线程调度程序会从可运行线程池中选择一个线程作为当前线程。这也是线程进入运行状态的唯一一种方式。
所以线程只能从,可运行状态进入运行中状态。
start()
方法,此线程进入就绪状态。yield()
方法,当前线程进入就绪状态。sleep()
方法结束,其他线程 join()
结束,等待用户输入完毕,某个线程拿到对象锁,这些线程也将进入就绪状态。Blocking 称为阻塞状态,或者说线程已经被挂起,原因通常是它在等待一个“锁”,当尝试进入一个 synchronized 语句块/方法时,锁已经被其它线程占有,就会被阻塞,直到另一个线程走完临界区或发生了相应锁对象的 wait() 操作后,它才有机会去争夺进入临界区的权利。
在 Java 代码中,需要考虑 synchronized 的粒度问题,否则一个线程长时间占用锁,其它争抢锁的线程会一直阻塞,直到拥有锁的线程释放锁。
处于 BLOCKED 状态的线程,即使对其调用 thread.interrupt() 也无法改变其阻塞状态,因为 interrupt() 方法只是设置线程的中断状态,即做一个标记,不能唤醒处于阻塞状态的线程。
等待其它线程显式地唤醒,否则不会被分配 CPU 时间片。
进入方法 | 退出方法 |
---|---|
没有设置 Timeout 参数的 Object.wait() 方法 | Object.notify() / Object.notifyAll() |
没有设置 Timeout 参数的 Thread.join() 方法 | 被调用的线程执行完毕 |
LockSupport.park() 方法 | - |
无需等待其它线程显式地唤醒,在一定时间之后会被系统自动唤醒。
调用 Thread.sleep()
方法使线程进入限期等待状态时,常常用“使一个线程睡眠”进行描述。
调用 Object.wait()
方法使线程进入限期等待或者无限期等待时,常常用“挂起一个线程”进行描述。
睡眠和挂起是用来描述行为,而阻塞和等待用来描述状态。
阻塞和等待的区别在于,阻塞是被动的,它是在等待获取一个排它锁。而等待是主动的,通过调用 Thread.sleep()
和 Object.wait()
等方法进入。
进入方法 | 退出方法 |
---|---|
Thread.sleep() 方法 | 时间结束 |
设置了 Timeout 参数的 Object.wait() 方法 | 时间结束 / Object.notify() / Object.notifyAll() |
设置了 Timeout 参数的 Thread.join() 方法 | 时间结束 / 被调用的线程执行完毕 |
LockSupport.parkNanos() 方法 | - |
LockSupport.parkUntil() 方法 | - |
可以是线程结束任务之后自己结束,或者产生了异常而结束。
其实这只是 Java 语言级别的一种状态,在操作系统内部可能已经注销了相应的线程,或者将它复用给其他需要使用线程的请求,而在 Java 语言级别只是通过 Java 代码看到的线程状态而已。
“阻塞”与“等待”的区别:
(1)“阻塞”状态是等待着获取到一个排他锁,进入“阻塞”状态都是被动的,离开“阻塞”状态是因为其它线程释放了锁,不阻塞了;
(2)“等待”状态是在等待一段时间 或者 唤醒动作的发生,进入“等待”状态是主动的;
如主动调用 Object.wait() ,如无法获取到 ReentraantLock ,主动调用 LockSupport.park() ,如主线程主动调用 subThread.join() ,让主线程等待子线程执行完毕再执行。
离开“等待”状态是因为其它线程发生了唤醒动作或者到达了等待时间。
https://www.cnblogs.com/javadevelper/p/6036472.html
https://www.pdai.tech/md/java/thread/java-thread-x-thread-basic.html
https://blog.csdn.net/qq_33565047/article/details/102958254
https://blog.csdn.net/wanliguodu/article/details/81005560
https://www.cnblogs.com/trust-freedom/p/6606594.html