面试官: 有了解过线程池的工作原理吗?说说看

前言

目前正在出一个Java多线程专题长期系列教程,从入门到进阶含源码解读, 篇幅会较多, 喜欢的话,给个关注❤️ ~

本节主要带大家从ThreadPoolExecutor源码角度来了解一下线程池的工作原理,一起来看下吧~

Executor 接口

首先Executor这个接口是线程池实现的顶层接口类,我们上节遇到的ExecutorService也是继承了Executor

 public void execute(Runnable command) {
        // 如果任务不存在 抛空异常
        if (command == null)
            throw new NullPointerException();
   
        // 获取当前状态值
        int c = ctl.get();
        // 当前线程数小于corePoolSize,则调用addWorker创建核心线程执行任务
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        // 如果不小于corePoolSize,则将任务添加到workQueue队列。
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            // 如果isRunning返回false(状态检查),则remove这个任务,然后执行拒绝策略。
            if (! isRunning(recheck) && remove(command))
                reject(command);
                // 线程池处于running状态,但是没有线程,则创建线程
            else if (workerCountOf(recheck) == 0)
                addWorker(nullfalse);
        }
        // 如果放入workQueue失败,则创建非核心线程执行任务,
        else if (!addWorker(command, false))
            // 如果这时创建失败,就会执行拒绝策略。
            reject(command);
    }

在源码中,我们可以看到,多次进行了isRunning判断。在多线程的环境下,线程池的状态是多变的。很有可能刚获取线程池状态后线程池状态就改变了

总结

下面给大家简要的总结一下线程池的处理流程

  1. 线程总数量小于线程池中保留的线程数量(corePoolSize),无论线程是否空闲,都会新建一个核心线程执行任务,这一步需要获取全局锁

  2. 线程总数量大于corePoolSize时,新来的线程任务会进入任务队列中等待,然后空闲的核心线程会依次去缓存队列中取任务来执行,从而达到线程的复用

  3. 当缓存队列满了,会创建非核心线程去执行这个任务。

  4. 缓存队列满了, 且总线程数达到了maximumPoolSize,则会采取拒绝策略进行处理。

结束语

它的源码还是比较长的,一篇文章说不清楚,有兴趣的同学可以通过本篇文章的理解继续阅读它的源码。

下一节, 继续带大家详探讨ThreadPoolExecutor中是如何进行线程复用

本篇文章来源于微信公众号: 程序员皮卡秋



微信扫描下方的二维码阅读本文

此作者没有提供个人介绍
最后更新于 2023-05-28