(手机横屏看源码更方便)
注:java源码分析部分如无特殊说明均基于 java8 版本。
简介大家都知道线程是有生命周期,但是彤哥可以认真负责地告诉你网上几乎没有一篇文章讲得是完全正确的。
常见的错误有:就绪状态、运行中状态(RUNNING)、死亡状态、中断状态、只有阻塞没有等待状态、流程图乱画等,最常见的错误就是说线程只有5种状态。
今天这篇文章会彻底讲清楚线程的生命周期,并分析synchronized锁、基于AQS的锁中线程状态变化的逻辑。
所以,对synchronized锁和AQS原理(源码)不了解的同学,请翻一下彤哥之前的文章先熟悉这两部分的内容,否则肯定记不住这里讲的线程生命周期。
问题(1)线程的状态有哪些?
(2)synchronized锁各阶段线程处于什么状态?
(3)重入锁、条件锁各阶段线程处于什么状态?
先上源码关于线程的生命周期,我们可以看一下java.lang.Thread.State这个类,它是线程的内部枚举类,定义了线程的各种状态,并且注释也很清晰。
public enum State { /** * 新建状态,线程还未开始 */ NEW, /** * 可运行状态,正在运行或者在等待系统资源,比如CPU */ RUNNABLE, /** * 阻塞状态,在等待一个监视器锁(也就是我们常说的synchronized) * 或者在调用了Object.wait()方法且被notify()之后也会进入BLOCKED状态 */ BLOCKED, /** * 等待状态,在调用了以下方法后进入此状态 * 1. Object.wait()无超时的方法后且未被notify()前,如果被notify()了会进入BLOCKED状态 * 2. Thread.join()无超时的方法后 * 3. LockSupport.park()无超时的方法后 */ WAITING, /** * 超时等待状态,在调用了以下方法后会进入超时等待状态 * 1. Thread.sleep()方法后【本文由公从号“彤哥读源码”原创】 * 2. Object.wait(timeout)方法后且未到超时时间前,如果达到超时了或被notify()了会进入BLOCKED状态 * 3. Thread.join(timeout)方法后 * 4. LockSupport.parkNanos(nanos)方法后 * 5. LockSupport.parkUntil(deadline)方法后 */ TIMED_WAITING, /** * 终止状态,线程已经执行完毕 */ TERMINATED; } 流程图线程生命周期中各状态的注释完毕了,下面我们再来看看各状态之间的流转:
怎么样?是不是很复杂?彤哥几乎把网上的资料都查了一遍,没有一篇文章把这个流程图完整画出来的,下面彤哥就来一一解释:
(1)为了方便讲解,我们把锁分成两大类,一类是synchronized锁,一类是基于AQS的锁(我们拿重入锁举例),也就是内部使用了LockSupport.park()/parkNanos()/parkUntil()几个方法的锁;
(2)不管是synchronized锁还是基于AQS的锁,内部都是分成两个队列,一个是同步队列(AQS的队列),一个是等待队列(Condition的队列);
(3)对于内部调用了object.wait()/wait(timeout)或者condition.await()/await(timeout)方法,线程都是先进入等待队列,被notify()/signal()或者超时后,才会进入同步队列;
(4)明确声明,BLOCKED状态只有线程处于synchronized的同步队列的时候才会有这个状态,其它任何情况都跟这个状态无关;
(5)对于synchronized,线程执行synchronized的时候,如果立即获得了锁(没有进入同步队列),线程处于RUNNABLE状态;
(6)对于synchronized,线程执行synchronized的时候,如果无法获得锁(直接进入同步队列),线程处于BLOCKED状态;
(5)对于synchronized内部,调用了object.wait()之后线程处于WAITING状态(进入等待队列);
(6)对于synchronized内部,调用了object.wait(timeout)之后线程处于TIMED_WAITING状态(进入等待队列);
(7)对于synchronized内部,调用了object.wait()之后且被notify()了,如果线程立即获得了锁(也就是没有进入同步队列),线程处于RUNNABLE状态;
(8)对于synchronized内部,调用了object.wait(timeout)之后且被notify()了,如果线程立即获得了锁(也就是没有进入同步队列),线程处于RUNNABLE状态;
(9)对于synchronized内部,调用了object.wait(timeout)之后且超时了,这时如果线程正好立即获得了锁(也就是没有进入同步队列),线程处于RUNNABLE状态;
(10)对于synchronized内部,调用了object.wait()之后且被notify()了,如果线程无法获得锁(也就是进入了同步队列),线程处于BLOCKED状态;