目录
一, 新建状态 (NEW)
二, 运行状态 (RUNNABLE)
就绪状态 (READY)
运行状态 (RUNNING)
三, 阻塞状态 (BLOCKED)
四, 等待状态 (WAITING)
运行 -> 等待
等待 -> 就绪
五, 超时等待状态 (TIMED_WAITING)
运行 -> 超时等待
超时等待 -> 就绪
六, 消亡状态
前文传送门: 多线程概述及创建方式
关于线程的生命周期, 网上书上说法不一, 难以统一, 本篇做一个总结:
java.lang.Thread.State 枚举类中定义了六种线程的状态, 可以调用线程 Thread 中的 getState() 方法获取当前线程的状态.
线程状态 | 解释 |
---|---|
NEW | 尚未启动的线程状态,即线程创建,还未调用 start 方法 |
RUNNABLE | 就绪状态 (调用 start,等待调度)+ 正在运行 |
BLOCKED | 等待监视器锁 时,陷入阻塞状态 |
WAITING | 等待状态的线程正在 < strong ztid="113" ow="28" oh="17">等待 另一线程执行特定的操作(如 notify) |
TIMED_WAITING | 具有 < strong ztid="117" ow="84" oh="17">指定等待时间 的等待状态 |
TERMINATED | 线程完成执行,终止状态 |
下图源自《Java 并发编程艺术》图 4-1
一, 新建状态 (NEW)
即用 new 关键字新建一个线程, 这个线程就处于新建状态.
二, 运行状态 (RUNNABLE)
操作系统中的就绪和运行两种状态, 在 Java 中统称为 RUNNABLE.
就绪状态 (READY)
当线程对象调用了 start() 方法之后, 线程处于就绪状态, 就绪意味着该线程可以执行, 但具体啥时候执行将取决于 JVM 里线程调度器的调度.
It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.
不允许对一个线程多次使用 start.
线程执行完成之后, 不能试图用 start 将其唤醒.
其他状态 -> 就绪
线程调用 start(), 新建状态转化为就绪状态.
线程 sleep(long) 时间到, 等待状态转化为就绪状态.
阻塞式 IO 操作结果返回, 线程变为就绪状态.
其他线程调用 join() 方法, 结束之后转化为就绪状态.
线程对象拿到对象锁之后, 也会进入就绪状态.
运行状态 (RUNNING)
处于就绪状态的线程获得了 CPU 之后, 真正开始执行 run() 方法的线程执行体时, 意味着该线程就已经处于运行状态. 需要注意的是, 对于单处理器, 一个时刻只能有一个线程处于运行状态.
对于抢占式策略的系统来说, 系统会给每个线程一小段时间处理各自的任务. 时间用完之后, 系统负责夺回线程占用的资源. 下一段时间里, 系统会根据一定规则, 再次进行调度.
运行状态转变为就绪状态的情形:
线程失去处理器资源. 线程不一定完整执行的, 执行到一半, 说不定就被别的线程抢走了.
调用 yield() 静态方法, 暂时暂停当前线程, 让系统的线程调度器重新调度一次, 它自己完全有可能再次运行.
yield 方法的官方解释:
A hint to the scheduler that the current thread is willing to yield its current use of a processor. The scheduler is free to ignore this hint.
提示调度程序, 当前线程愿意放弃当前对处理器的使用. 这时, 当前线程将会被置为就绪状态, 和其他线程一样等待调度, 这时候根据不同优先级决定的概率, 当前线程完全有可能再次抢到处理器资源.
三, 阻塞状态 (BLOCKED)
阻塞状态表示线程正等待监视器锁, 而陷入的状态.
以下场景线程将会阻塞:
线程等待进入 synchronized 同步方法.
线程等待进入 synchronized 同步代码块.
线程取得锁, 就会从阻塞状态转变为就绪状态.
四, 等待状态 (WAITING)
进入该状态表示当前线程需要等待其他线程做出一些的特定的动作 (通知或中断).
运行 -> 等待
当前线程运行过程中, 其他线程调用 join 方法, 当前线程将会进入等待状态.
当前线程对象调用 wait() 方法.
-LockSupport.park(): 出于线程调度的目的禁用当前线程.
等待 -> 就绪
等待的线程被其他线程对象唤醒, notify() 和 notifyAll().
LockSupport.unpark(Thread)
, 与上面 park 方法对应, 给出许可证, 解除等待状态.
五, 超时等待状态 (TIMED_WAITING)
区别于 WAITING, 它可以在指定的时间自行返回.
运行 -> 超时等待
调用静态方法, Thread.sleep(long)
线程对象调用 wait(long) 方法
其他线程调用指定时间的 join(long).
- LockSupport.parkNanos()
- .
- LockSupport.parkUntil()
- .
补充:
sleep 和 yield 的不同之处:
sleep(long) 方法会使线程转入超时等待状态, 时间到了之后才会转入就绪状态. 而 yield() 方法不会将线程转入等待, 而是强制线程进入就绪状态.
使用 sleep(long) 方法需要处理异常, 而 yield() 不用.
超时等待 -> 就绪
同样的, 等待的线程被其他线程对象唤醒, notify() 和 notifyAll().
- LockSupport.unpark(Thread)
- .
六, 消亡状态
即线程的终止, 表示线程已经执行完毕. 前面已经说了, 已经消亡的线程不能通过 start 再次唤醒.
run() 和 call() 线程执行体中顺利执行完毕, 线程正常终止.
线程抛出一个没有捕获的 Exception 或 Error.
需要注意的是: 主线成和子线程互不影响, 子线程并不会因为主线程结束就结束.
许多地方仍需后期补充, 敬请期待.
参考资料:《JAVA 并发编程实践》,《疯狂 Java 讲义》,《Java 并发编程艺术》
来源: https://www.cnblogs.com/summerday152/p/12288671.html