- 在线客服 
  - 扫描二维码 
 下载博学谷APP
  - 扫描二维码 
 关注博学谷微信公众号
ThreadPoolExecutor里面使用到JUC同步器框架AbstractQueuedSynchronizer、大量的位操作、CAS操作。ThreadPoolExecutor提供了固定活跃线程、额外的线程、任务队列以及拒绝策略这几个重要的功能。下面我们一起来看看Java 线程池ThreadPoolExecutor的原理解析。

1、JUC同步器框架
ThreadPoolExecutor里面使用到JUC同步器框架,主要用于四个方面:
(1)全局锁mainLock成员属性,是可重入锁ReentrantLock类型,主要是用于访问工作线程Worker集合和进行数据统计记录时候的加锁操作。
(2)条件变量termination,Condition类型,主要用于线程进行等待终结awaitTermination()方法时的带期限阻塞。
(3)任务队列workQueue,BlockingQueue类型,任务队列,用于存放待执行的任务。
(4)工作线程,内部类Worker类型,是线程池中真正的工作线程对象。
2、核心线程
这里先参考ThreadPoolExecutor的实现并且进行简化,实现一个只有核心线程的线程池,要求如下:暂时不考虑任务执行异常情况下的处理;任务队列为无界队列;线程池容量固定为核心线程数量;暂时不考虑拒绝策略。
public class CoreThreadPool implements Executor {
    private BlockingQueue<Runnable> workQueue;
    private static final AtomicInteger COUNTER = new AtomicInteger();
    private int coreSize;
    private int threadCount = 0;
    public CoreThreadPool(int coreSize) {
        this.coreSize = coreSize;
        this.workQueue = new LinkedBlockingQueue<>();
    }
    @Override
    public void execute(Runnable command) {
        if (++threadCount <= coreSize) {
            new Worker(command).start();
        } else {
            try {
                workQueue.put(command);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
        }
    }
    private class Worker extends Thread {
        private Runnable firstTask;
        public Worker(Runnable runnable) {
            super(String.format("Worker-%d", COUNTER.getAndIncrement()));
            this.firstTask = runnable;
        }
        @Override
        public void run() {
            Runnable task = this.firstTask;
            while (null != task || null != (task = getTask())) {
                try {
                    task.run();
                } finally {
                    task = null;
                }
            }
        }
    }
    private Runnable getTask() {
        try {
            return workQueue.take();
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }
    public static void main(String[] args) throws Exception {
        CoreThreadPool pool = new CoreThreadPool(5);
        IntStream.range(0, 10)
                .forEach(i -> pool.execute(() ->
                        System.out.println(String.format("Thread:%s,value:%d", Thread.currentThread().getName(), i))));
        Thread.sleep(Integer.MAX_VALUE);
    }
}
某次运行结果如下:
Thread:Worker-0,value:0
Thread:Worker-3,value:3
Thread:Worker-2,value:2
Thread:Worker-1,value:1
Thread:Worker-4,value:4
Thread:Worker-1,value:5
Thread:Worker-2,value:8
Thread:Worker-4,value:7
Thread:Worker-0,value:6
Thread:Worker-3,value:9
设计此线程池的时候,核心线程是懒创建的,如果线程空闲的时候则阻塞在任务队列的take()方法,其实对于ThreadPoolExecutor也是类似这样实现,只是如果使用了keepAliveTime并且允许核心线程超时则会使用BlockingQueue#poll进行轮询代替永久阻塞。
3、其他附加功能
构建ThreadPoolExecutor实例的时候,需要定义maximumPoolSize(线程池最大线程数)和corePoolSize(核心线程数)。当任务队列是有界的阻塞队列,核心线程满负载,任务队列已经满的情况下,会尝试创建额外的maximumPoolSize - corePoolSize个线程去执行新提交的任务。当ThreadPoolExecutor这里实现的两个主要附加功能是:
(1)一定条件下会创建非核心线程去执行任务,非核心线程的回收周期(线程生命周期终结时刻)是keepAliveTime,线程生命周期终结的条件是:下一次通过任务队列获取任务的时候并且存活时间超过keepAliveTime。
(2)提供拒绝策略,也就是在核心线程满负载、任务队列已满、非核心线程满负载的条件下会触发拒绝策略。
以上就是Java 线程池ThreadPoolExecutor的原理解析,大家都看懂了吗?如果想要深入学习更多关于Java 线程池的内容,欢迎大家在博学谷报名在线课程进行学习~
— 申请免费试学名额 —
    在职想转行提升,担心学不会?根据个人情况规划学习路线,闯关式自适应学习模式保证学习效果
    
    讲师一对一辅导,在线答疑解惑,指导就业!
  
相关推荐 更多
  - Docker开发教程学习资源
 - Docker开发教程学习资源,需要学习Docker概览、Docker版本与安装介绍、Docker核心技术之镜像、Docker核心技术之容器、Docker核心技术之容器与镜像、Docker核心技术之数据卷、Docker核心技术之仓库、Docker核心技术之Dockerfile、Docker核心技术之Docker-Compose。 - 4956 - 2019-11-11 19:14:44 
  - Java技术未来发展前景如何?
 - Java编程语言一直以来都是使用率最高的编程语言之一,由于Java具有安全性能高、可移植性、可拓展等特点,目前Java被国内外大型企业所推崇。对于Java技术未来发展前景,主要从从业者职业发展和发展领域、语言本身等几个方面来看。 - 5606 - 2019-11-19 18:25:05 
  - 线程池经典面试题整理附答案
 - 线程池是一种多线程处理形式,它是Java开发面试中的必考知识点,尤其是在一些大厂的求职面试中,线程池是对求职者考核的重点。为了帮助大家可以更好地通过面试,本文特地为大家整理了线程池经典面试题并附上了答案,下面一起来尝试着做一做吧! - 9281 - 2020-06-17 14:44:17 
  - Java内存模型JMM基础知识及原理
 - Java内存模型JMM基础知识及原理,学习过程中需要了解内存模型抽象结构、共享变量、JMM抽象结构模型、主内存与工作内存的相关知识,Java内存模型具有原子性、可见性、有序性三大特征。 - 4940 - 2020-07-27 11:58:33 
  - 从0开始学Java开发要做哪些准备?
 - 很多从0开始学Java开发的初学者,常常在面对一大堆基础语法知识的时候,感到无从下手。其实这也是很正常的现象,毕竟编程的学习门槛虽然很低,但是学起来并不轻松,想要学好更是难上加难。那么,我们应该在学习之前做哪些准备呢?换句话说,作为零基础的初学者,我们应该如何开始Java开发的学习呢? - 4930 - 2020-08-03 11:47:20 
 
  
  
 