深度理解Java线程池ThreadPoolExecutor

一.使用线程池的好处

1.提高系统性能和响应速度:线程池可以通过复用线程来减少线程的创建和销毁,从而减少了系统开销,提高了系统的性能和响应速度。

2.提高代码的可维护性:使用线程池可以将任务的执行与线程的创建和管理分离开来,使得代码更加清晰易懂,也更加容易维护。

3.提高代码的可复用性:线程池可以让不同的任务共享同一个线程池,从而提高代码的可复用性。

二.ThreadPoolExecutor线程池的参数解释

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

1.corePoolSize:核心线程池大小,即线程池中保留的线程数,即使它们处于空闲状态。如果新的任务提交给线程池时,核心线程池中的线程都在忙碌状态,那么新任务就会被添加到工作队列中等待执行。

2.maximumPoolSize:最大线程池大小,即线程池中最多可以创建的线程数。如果工作队列已满并且线程池中的线程数小于最大线程池大小,则会创建新的线程来执行任务。

3.keepAliveTime:空闲线程存活时间,即当一个线程处于空闲状态时,它最多可以存活多长时间。如果线程池中的线程数超过了核心线程池大小,空闲的线程将会被回收,直到线程池中的线程数等于核心线程池大小为止。

4.unit:keepAliveTime的时间单位。

5.workQueue:任务队列,用于存储等待执行的任务。当所有的核心线程都在执行任务时,新的任务会被添加到任务队列中等待执行。任务队列有多种实现方式,例如ArrayBlockingQueue、LinkedBlockingQueue等。

三.线程池的执行流程(execute方法)

        public void execute(Runnable command) {
            if (command == null)
                throw new NullPointerException();
            /**
             * ctl中保存了两个信息,高3位保存的是线程池状态,低29位保存的是线程数量,
             * ctl.get()方法用于检查线程池状态和线程数量
             */
            int c = ctl.get();
            /**
             * 第一阶段:如果线程中的线程数小于核心线程数,那么就将线程添加到线程池中,
             * 此时添加的线程类型是核心线程,占用corePoolSize的名额,添加成功则直接返回
             * 如果核心线程池已满,则刷新线程池状态并执行第二阶段
             */
            if (workerCountOf(c) < corePoolSize) {
                if (addWorker(command, true))
                    return;
                c = ctl.get();
            }
            /**
             * 第二阶段:如果核心线程数已满,则检查线程池运行状态,如果运行状态正常,
             * 则执行workQueue.offer(command)方法,即添加线程到任务队列,成功则返回true,之后再次刷新线程池状态,
             * 如果线程池不是running状态或者任务队列已满,则执行第三阶段
             */
            if (isRunning(c) && workQueue.offer(command)) {
                int recheck = ctl.get();
                /**
                 * 如果线程池不是running状态,则执行remove(command)方法,即从队列中移出任务,并执行拒绝策略
                 */
                if (! isRunning(recheck) && remove(command))
                    reject(command);
                /**
                 * 如果线程池是running状态或者移出失败,则检测线程数量是否为0,
                 * 线程数量为0则添加线程到线程池中,此时添加的线程是非核心线程,且不执行任务
                 * 否则执行拒绝策略
                 */
                else if (workerCountOf(recheck) == 0)
                    addWorker(null, false);
            }
            /**
             * 第三阶段:如果任务队列已满,则添加线程到线程池中,这时添加的是非核心线程,
             * 占用maximumPoolSize的名额,若添加失败,即maximumPoolSize已满,则执行拒绝策略
             */
            else if (!addWorker(command, false))
                reject(command);
        }

1.当有任务需要执行时,首先判断当前线程池中的线程数是否小于核心线程数,如果是,则创建一个新的核心线程来执行任务。

2.如果当前线程池中的线程数已经达到核心线程数,则将任务放入任务队列中等待执行。

3.当任务队列已满时,如果当前线程池中的线程数还没有达到最大线程数,则创建新的非核心线程来执行任务。

4.如果当前线程池中的线程数已经达到最大线程数,则采取拒绝策略,例如抛出异常或者执行一些默认操作。

posted @   shaun23  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示