博学谷 > 资讯 > Java > Java线程池ThreadPoolExecutor的原理解析

原创 Java线程池ThreadPoolExecutor的原理解析

发布时间:2020-05-27 14:56:59 浏览 490 来源:博学谷 作者:照照

    ThreadPoolExecutor里面使用到JUC同步器框架AbstractQueuedSynchronizer、大量的位操作、CAS操作。ThreadPoolExecutor提供了固定活跃线程、额外的线程、任务队列以及拒绝策略这几个重要的功能。下面我们一起来看看Java 线程池ThreadPoolExecutor的原理解析。

     

    Java线程池

     

    1JUC同步器框架

     

    ThreadPoolExecutor里面使用到JUC同步器框架,主要用于四个方面:

     

    1)全局锁mainLock成员属性,是可重入锁ReentrantLock类型,主要是用于访问工作线程Worker集合和进行数据统计记录时候的加锁操作。

     

    2)条件变量terminationCondition类型,主要用于线程进行等待终结awaitTermination()方法时的带期限阻塞。

     

    3)任务队列workQueueBlockingQueue类型,任务队列,用于存放待执行的任务。

     

    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 线程池的内容,欢迎大家在博学谷报名在线课程进行学习~

    申请免费试学名额    

在职想转行提升,担心学不会?根据个人情况规划学习路线,闯关式自适应学习模式保证学习效果
讲师一对一辅导,在线答疑解惑,指导就业!

领取成功
领取失败
上一篇:Java方法重载学习总结 下一篇:Java基础练习之评委打分

相关推荐 更多

最新文章

扫描二维码,回复"Java"获取180G资料包

4887铁算结果开奖结果小说