线程是比进程更加轻量级的调度执行单位,理解线程是理解并发编程的不可或缺的一部分;而生产过程当中不可能永远使用裸线程,须要线程池技术,线程池是管理和调度线程的资源池。由于前不久遇到了一个关于线程状态的问题,今天就趁热打铁从源码的层面来谈一谈线程和线程池的状态及状态之间的转移。编程
JDK中,线程(Thread)定义了6种状态: NEW(新建)、RUNNABLE(可执行)、BLOCKED(阻塞)、WAITING(等待)、TIMED_WAITING(限时等待)、TERMINATED(结束)。缓存
源码以下:并发
/** * A thread state. A thread can be in one of the following states: * <ul> * <li>{@link #NEW} * A thread that has not yet started is in this state. * </li> * <li>{@link #RUNNABLE} * A thread executing in the Java virtual machine is in this state. * </li> * <li>{@link #BLOCKED} * A thread that is blocked waiting for a monitor lock * is in this state. * </li> * <li>{@link #WAITING} * A thread that is waiting indefinitely for another thread to * perform a particular action is in this state. * </li> * <li>{@link #TIMED_WAITING} * A thread that is waiting for another thread to perform an action * for up to a specified waiting time is in this state. * </li> * <li>{@link #TERMINATED} * A thread that has exited is in this state. * </li> * </ul> * * <p> * A thread can be in only one state at a given point in time. * These states are virtual machine states which do not reflect * any operating system thread states. * * @since 1.5 * @see #getState */ public enum State { /** * Thread state for a thread which has not yet started. */ NEW, /** * Thread state for a runnable thread. A thread in the runnable * state is executing in the Java virtual machine but it may * be waiting for other resources from the operating system * such as processor. */ RUNNABLE, /** * 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}. */ BLOCKED, /** * Thread state for a waiting thread. * A thread is in the waiting state due to calling one of the * following methods: * <ul> * <li>{@link Object#wait() Object.wait} with no timeout</li> * <li>{@link #join() Thread.join} with no timeout</li> * <li>{@link LockSupport#park() LockSupport.park}</li> * </ul> * * <p>A thread in the waiting state is waiting for another thread to * perform a particular action. * * For example, a thread that has called <tt>Object.wait()</tt> * on an object is waiting for another thread to call * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on * that object. A thread that has called <tt>Thread.join()</tt> * is waiting for a specified thread to terminate. */ WAITING, /** * Thread state for a waiting thread with a specified waiting time. * A thread is in the timed waiting state due to calling one of * the following methods with a specified positive waiting time: * <ul> * <li>{@link #sleep Thread.sleep}</li> * <li>{@link Object#wait(long) Object.wait} with timeout</li> * <li>{@link #join(long) Thread.join} with timeout</li> * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li> * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li> * </ul> */ TIMED_WAITING, /** * Thread state for a terminated thread. * The thread has completed execution. */ TERMINATED; }
线程在一个给定的时间点只能处于下面其中一种状态:源码分析
这些状态是虚拟机状态,并不能反映任何操做系统的线程状态。this
NEW:线程还没有启动的线程状态。当在程序中建立一个线程的时候Thread t = new Thread(Runnable);,线程处于NEW状态。spa
RUNNABLE:可运行线程的线程状态。处于可运行状态的线程正在Java虚拟机中执行,但它可能正在等待操做系统中的其余资源,好比处理器。也就是说, 这个状态就是可运行可不运行的状态。注意Runnable ≠ Running。操作系统
BLOCKED:等待监视器锁的阻塞线程的线程状态。好比,线程试图经过synchronized去获取某个锁,可是其余线程已经独占了,那么当前线程就会处于阻塞状态。处于阻塞状态的线程正在等待监视器锁去进入同步块/方法(等待一个监视器锁时为了进入同步块/方法),或者在调用Object.wait()后从新进入同步块/方法。线程
WAITING:调用如下方法之一,线程会处于等待状态:翻译
其实wait()方法有多重形式,能够不带参数,能够带参数,参数表示等待时间(单位ms),如图所示:code
“BLOCKED(阻塞状态)”和“WAITING(等待状态)”的区别:阻塞状态在等待获取一个排它锁,这个事件将会在另一个线程放弃这个锁的时候发生,而后由阻塞状态变为可执行状态;而等待状态则是在等待一段时间,或者等待唤醒动做的发生。
TIMED_WAITING:一个线程调用了如下方法之一(方法须要带具体的等待时间),会处于定时等待状态:
TERMINATED: 该线程已经执行完毕。
其实这些大部分在源码的注释中能够找到。下面我本身翻译的中文版,不嫌弃的话能够参考:
/** * 线程状态。 一个线程能够处于下列状态之一: * * NEW:还没有启动的线程处于这个状态。 * * RUNNABLE:正在Java虚拟机中执行的线程处于这个状态。 * * BLOCKED:阻塞中,等待监视器锁的线程处于这个状态。 * * WAITING:无限期等待另外一个线程执行特定操做的线程处于这种状态。 * * TIMED_WAITING:正在等待另外一个线程执行某个操做的线程在指定的等待时间内处于这种状态。 * * TERMINATED:已经退出的线程处于这个状态。 * * 线程在一个给定的时间点只能处于一种状态。 * 这些状态是虚拟机状态,并不能反映任何操做系统的线程状态。 * */ public enum State { /** * 线程还没有启动的线程状态。 */ NEW, /** * 可运行线程的线程状态。处于可运行状态的线程正在Java虚拟机中执行, * 但它可能正在等待操做系统中的其余资源,好比处理器。 */ RUNNABLE, /** * 等待监视器锁的阻塞线程的线程状态。 * 处于阻塞状态的线程正在等待监视器锁进入同步块/方法, * 或者在调用Object.wait后从新进入同步块/方法。 */ BLOCKED, /** * 等待线程的线程状态。 * 调用如下方法之一,线程会处于等待状态: * Object.wait()注意:括号内不带参数; * Thread.join()注意:扩号内不带参数; * LockSupport.park(); * * 处于等待状态的线程正在等待另一个线程执行特定的操做。 * * 例如,一个调用了object.wait()方法的线程正在等待另一下线程调用 * object.notify()或者object.notifyAll()方法。注意,这两个object是同一个object。 * 一个调用了Thread.join()方法的线程正在等待一个特定的线程去终止。 */ WAITING, /** * 具备指定等待时间的等待线程的线程状态。 * 一个线程调用了如下方法之一(方法须要带具体的等待时间),会处于定时等待状态: * Thread.sleep(timeout) * Object.wait(timeout) * Thread.join(timeout) * LockSupport.parkNanos() * LockSupport.parkUntil() */ TIMED_WAITING, /** * 终止的线程状态。 * 该线程已经执行完毕。 */ TERMINATED; }
状态转移图如图所示:
在生产环境中,为每一个任务分配一个线程是存在缺陷的,例如资源消耗和稳定性等,因此须要使用线程池。
Java类库提供了灵活的线程池,能够调用Executors中的静态工厂方法建立线程池。如
无论是newFixedThreadPool仍是newCachedThreadPool,底层都是经过ThreadPoolExecutor实现的,本文只谈ThreadPoolExecutor的状态。
在JDK源码中,线程池(ThreadPoolExecutor)定义了五种状态:RUNNING、SHUTDOWN、STOP、TIDYING和TERMINATED。
源码以下:
private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS;
RUNNING — 运行状态,能够添加新任务,也能够处理阻塞队列中的任务。
SHUTDOWN — 待关闭状态,再也不接受新的任务,会继续处理阻塞队列中的任务。
STOP — 中止状态,再也不接受新的任务,不会执行阻塞队列中的任务,打断正在执行的任务。
TIDYING — 整理状态,全部任务都处理完毕,workerCount为0,线程转到该状态将会运行terminated()钩子方法。
TERMINATED — 终止状态,terminated()方法执行完毕。
* RUNNING -> SHUTDOWN * On invocation of shutdown(), perhaps implicitly in finalize() * (RUNNING or SHUTDOWN) -> STOP * On invocation of shutdownNow() * SHUTDOWN -> TIDYING * When both queue and pool are empty * STOP -> TIDYING * When pool is empty * TIDYING -> TERMINATED * When the terminated() hook method has completed
线程池的初始化状态是RUNNING。换句话说,线程池被一旦被建立,就处于RUNNING状态,而且线程池中的任务数为0。
当线程池处于RUNNING状态时,调用shutdown()方法,线程池RUNNING状态转为SHUTDOWN状态。
当线程池处于RUNNING or SHUTDOWN时,调用shutdownNow()方法时,线程池由(RUNNING or SHUTDOWN )状态转为STOP状态。
当线程池在SHUTDOWN状态下,阻塞队列为空而且线程池中执行的任务也为空时,就会由 SHUTDOWN状态转为TIDYING状态。
当线程池处于STOP状态,当线程池中执行的任务为空的时候,线程池有STOP状态转为TIDYING状态。
当线程池处于TIDYING状态,当执行完terminated()以后,就会由TIDYING状态转为TERMINATED状态。
状态转移图如图所示:
理解线程和线程池对于咱们平常开发或者诊断分析,都是不可或缺的基础。本文从源码分析了线程和线程池的状态和各类方法之间的对应关系,但愿对你们有帮助,文中若是有地方不妥还请你们指正。