从源码解读线程(Thread)和线程池(ThreadPoolExecutor)的状态

线程是比进程更加轻量级的调度执行单位,理解线程是理解并发编程的不可或缺的一部分;而生产过程中不可能永远使用裸线程,需要线程池技术,线程池是管理和调度线程的资源池。因为前不就遇到了一个关于线程状态的问题,今天就趁热打铁从源码的层面来谈一谈线程和线程池的状态及状态之间的转移。

线程

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;
    }

状态说明

线程在一个给定的时间点只能处于下面其中一种状态:

这些状态是虚拟机状态,并不能反映任何操作系统的线程状态。

  • NEW:尚未启动的线程处于这个状态。
  • RUNNABLE:正在Java虚拟机中执行的线程处于这个状态。
  • BLOCKED:阻塞,等待监视器锁的线程处于这个状态。
  • WAITING:无限期等待另一个线程执行特定操作的线程处于这种状态。
  • TIMED_WAITING:正在等待另一个线程执行某个操作的线程在指定的等待时间内处于这种状态。
  • TERMINATED:已经退出的线程处于这个状态。

状态转移

NEW:线程尚未启动的线程状态。当在程序中创建一个线程的时候Thread t = new Thread(Runnable);,线程处于NEW状态。

RUNNABLE:可运行线程的线程状态。处于可运行状态的线程正在Java虚拟机中执行,但它可能正在等待操作系统中的其他资源,比如处理器。也就是说, 这个状态就是可运行可不运行的状态。注意Runnable ≠ Running。

BLOCKED:等待监视器锁的阻塞线程的线程状态。比如,线程试图通过synchronized去获取某个锁,但是其他线程已经独占了,那么当前线程就会处于阻塞状态。处于阻塞状态的线程正在等待监视器锁去进入同步块/方法(等待一个监视器锁时为了进入同步块/方法),或者在调用Object.wait()后重新进入同步块/方法。

WAITING:调用以下方法之一,线程会处于等待状态:

  • Object.wait()注意:括号内不带参数;
  •  Thread.join()注意:扩号内不带参数;
  •  LockSupport.park();

其实wait()方法有多重形式,可以不带参数,可以带参数,参数表示等待时间(单位ms),如图所示:

“BLOCKED(阻塞状态)”和“WAITING(等待状态)”的区别:阻塞状态在等待获取一个排它锁,这个事件将会在另外一个线程放弃这个锁的时候发生,然后由阻塞状态变为可执行状态;而等待状态则是在等待一段时间,或者等待唤醒动作的发生。

TIMED_WAITING:一个线程调用了以下方法之一(方法需要带具体的等待时间),会处于定时等待状态:

  • Thread.sleep(long timeout)
  • Object.wait(long timeout)
  • Thread.join(long timeout)
  • LockSupport.parkNanos()
  • LockSupport.parkUntil()

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:可缓存的线程池。

不管是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状态。

状态转移图如图所示:

总结

理解线程和线程池对于我们日常开发或者诊断分析,都是不可或缺的基础。本文从源码分析了线程和线程池的状态和各种方法之间的对应关系,希望对大家有帮助,文中如果有地方不妥还请大家指正。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
线程池ThreadPoolExecutor)是 Java 中用于管理和执行线程的机制。下面是ThreadPoolExecutor源码的剖析: ```java public class ThreadPoolExecutor extends AbstractExecutorService { // 省略其他成员变量 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { // 根据参数创建线程池 } // 省略其他构造方法和方法重载 public void execute(Runnable command) { // 执行任务,将任务提交给线程池进行处理 } // 省略其他方法 private void runWorker(Worker w) { // 工作线程执行具体任务的逻辑 Runnable task = w.firstTask; w.firstTask = null; boolean completedAbruptly = true; try { while (task != null || (task = getTask()) != null) { // 执行任务 task.run(); task = null; } completedAbruptly = false; } finally { processWorkerExit(w, completedAbruptly); } } // 省略其他内部类和方法 } ``` 上述代码展示了ThreadPoolExecutor的主要结构。它是一个实现了ExecutorService接口的具体类,在Java中用于执行和管理线程池。 在构造方法中,我们可以设置核心线程数(corePoolSize)、最大线程数(maximumPoolSize)、空闲线程的存活时间(keepAliveTime)、时间单位(unit)和阻塞队列(workQueue)等参数。 execute方法用于向线程池提交任务,任务将被封装成一个Runnable对象,然后由线程池中的工作线程执行。 runWorker方法被工作线程调用,用于执行具体的任务逻辑。它不断地从阻塞队列中获取任务并执行,直到阻塞队列为空或工作线程被中断。 这只是ThreadPoolExecutor源码的简要剖析,了解更多细节可以查看源码实现。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

James Shangguan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值