Java实例教程:ThreadPoolExecutor的原理解析

Java实例教程:ThreadPoolExecutor的原理解析

北大青鸟长沙麓谷校区      2022-04-27 06:00:01     9

Java实例教程:ThreadPoolExecutor的原理解析,ThreadPoolExecutor里面使用到JUC同步器框架AbstractQueuedSynchronizer、大量的位操作、CAS操作。ThreadPoolExecutor提供了固定

课程价格 请咨询

上课时段: 授课校区:

详细介绍

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:0Thread:Worker-3,value:3Thread:Worker-2,value:2Thread:Worker-1,value:1Thread:Worker-4,value:4Thread:Worker-1,value:5Thread:Worker-2,value:8Thread:Worker-4,value:7Thread:Worker-0,value:6Thread:Worker-3,value:9

设计此线程池的时候,核心线程是懒创建的,如果线程空闲的时候则阻塞在任务队列的take()方法,其实对于ThreadPoolExecutor也是类似这样实现,只是如果使用了keepAliveTime并且允许核心线程超时则会使用BlockingQueue#poll进行轮询代替永久阻塞。

3.其他附加功能

构建ThreadPoolExecutor实例的时候,需要定义maximumPoolSize(线程池最大线程数)和corePoolSize(核心线程数)。当任务队列是有界的阻塞队列,核心线程满负载,任务队列已经满的情况下,会尝试创建额外的maximumPoolSize-corePoolSize个线程去执行新提交的任务。当ThreadPoolExecutor这里实现的两个主要附加功能是:

(1)一定条件下会创建非核心线程去执行任务,非核心线程的回收周期(线程生命周期终结时刻)是keepAliveTime,线程生命周期终结的条件是:下一次通过任务队列获取任务的时候并且存活时间超过keepAliveTime。

(2)提供拒绝策略,也就是在核心线程满负载、任务队列已满、非核心线程满负载的条件下会触发拒绝策略。

以上就是北大青鸟长沙麓谷校区java培训机构的小编针对“Java实例教程:ThreadPoolExecutor的原理解析”的内容进行的回答,希望对大家有所帮助,如有疑问,请在线咨询,有专业老师随时为你服务。

培训啦提醒您:交易时请核实对方资质,对于过大宣传或承诺需谨慎!任何要求预付定金、汇款等方式均存在风险,谨防上当。