线程池-动态更新线程池参数

线程池-动态更新线程池参数

import java.util.concurrent.*;

public class ThreadChangeDemo {
    public static void main(String[] args) throws InterruptedException {
        dynamicModifyExecutor();
    }
    /**
     * 自定义线程池
     * */
    private static ThreadPoolExecutor buildThreadPoolExecutor(){
        return new ThreadPoolExecutor(2, 5, 60, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10),
                new ThreadPoolExecutor.CallerRunsPolicy());
    }

    /**
     * 提交任务给线程池,修改线程池参数
     * */

    private static void dynamicModifyExecutor() throws InterruptedException {
        ThreadPoolExecutor executor = buildThreadPoolExecutor();
        for (int i=0;i<15;i++){
            executor.submit(()->{
                threadPoolStatus(executor,"创建任务");
                try {
                    TimeUnit.SECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //System.out.println(Thread.currentThread().getName()+"当前线程完成任务");
            });
        }
        threadPoolStatus(executor,"改变之前");
        TimeUnit.SECONDS.sleep(1);
        executor.setCorePoolSize(10);
        executor.setMaximumPoolSize(10);
        executor.prestartAllCoreThreads();
        threadPoolStatus(executor,"改变之后");
        Thread.currentThread().join();
    }

    /**
     * 打印线程池状态
     * */
    private static void threadPoolStatus(ThreadPoolExecutor executor,String name){
        LinkedBlockingQueue queue= (LinkedBlockingQueue) executor.getQueue();
        System.out.println(Thread.currentThread().getName()+"-"+name+"-:"+
                " 核心线程数:"+executor.getCorePoolSize()+
                " 活动线程数:"+executor.getActiveCount()+
                " 最大线程数:"+executor.getMaximumPoolSize()+
                " 线程池活跃度:"+divide(executor.getActiveCount(),executor.getMaximumPoolSize())+
                " 任务完成数:"+executor.getCompletedTaskCount()+
                " 队列大小:"+(queue.size()+queue.remainingCapacity())+
                " 当前排队线程数:"+queue.size()+
                " 队列剩余大小:"+queue.remainingCapacity()+
                " 队列使用度:"+divide(queue.size(),queue.size()+queue.remainingCapacity()));
    }

    /**
     *保留两位小数
     * */
    private static String divide(int num1,int num2){
        return String.format("%1.2f%%",Double.parseDouble(num1+"")/Double.parseDouble(num2+"")*100);
    }
}

上面的程序就是自定义了一个核心线程数为 2,最大线程数为 5,队列长度为 10 的线程池。

然后给它塞 15 个耗时 10 秒的任务,直接让它 5 个最大线程都在工作,队列长度 10 个都塞满。

当前的情况下,队列里面的 10 个,前 5 个在 10 秒后会被执行,后 5 个在 20 秒后会被执行。

再加上最大线程数正在执行的 5 个,15 个任务全部执行完全需要 3 个 10 秒即 30 秒的时间。

这个时候,如果我们把核心线程数和最大线程数都修改为 10。

那么 10 个任务会直接被 10 个最大线程数接管,10 秒就会被处理完成。

剩下的 5 个任务在队列里面,在 10 秒后被执行完成。

所以,15 个任务执行完成需要 2 个 10 秒即 20 秒的时间处理完成了。

看一下上面程序的打印日志:

pool-1-thread-3-创建任务-: 核心线程数:2 活动线程数:5 最大线程数:5 线程池活跃度:100.00% 任务完成数:0 队列大小:10 当前排队线程数:10 队列剩余大小:0 队列使用度:100.00%
pool-1-thread-2-创建任务-: 核心线程数:2 活动线程数:5 最大线程数:5 线程池活跃度:100.00% 任务完成数:0 队列大小:10 当前排队线程数:10 队列剩余大小:0 队列使用度:100.00%
pool-1-thread-1-创建任务-: 核心线程数:2 活动线程数:5 最大线程数:5 线程池活跃度:100.00% 任务完成数:0 队列大小:10 当前排队线程数:10 队列剩余大小:0 队列使用度:100.00%
pool-1-thread-5-创建任务-: 核心线程数:2 活动线程数:5 最大线程数:5 线程池活跃度:100.00% 任务完成数:0 队列大小:10 当前排队线程数:10 队列剩余大小:0 队列使用度:100.00%
main-改变之前-: 核心线程数:2 活动线程数:5 最大线程数:5 线程池活跃度:100.00% 任务完成数:0 队列大小:10 当前排队线程数:10 队列剩余大小:0 队列使用度:100.00%
pool-1-thread-4-创建任务-: 核心线程数:2 活动线程数:5 最大线程数:5 线程池活跃度:100.00% 任务完成数:0 队列大小:10 当前排队线程数:10 队列剩余大小:0 队列使用度:100.00%
pool-1-thread-12-创建任务-: 核心线程数:10 活动线程数:9 最大线程数:10 线程池活跃度:90.00% 任务完成数:0 队列大小:10 当前排队线程数:6 队列剩余大小:4 队列使用度:60.00%
pool-1-thread-13-创建任务-: 核心线程数:10 活动线程数:9 最大线程数:10 线程池活跃度:90.00% 任务完成数:0 队列大小:10 当前排队线程数:6 队列剩余大小:4 队列使用度:60.00%
pool-1-thread-15-创建任务-: 核心线程数:10 活动线程数:10 最大线程数:10 线程池活跃度:100.00% 任务完成数:0 队列大小:10 当前排队线程数:5 队列剩余大小:5 队列使用度:50.00%
main-改变之后-: 核心线程数:10 活动线程数:10 最大线程数:10 线程池活跃度:100.00% 任务完成数:0 队列大小:10 当前排队线程数:5 队列剩余大小:5 队列使用度:50.00%
pool-1-thread-14-创建任务-: 核心线程数:10 活动线程数:10 最大线程数:10 线程池活跃度:100.00% 任务完成数:0 队列大小:10 当前排队线程数:5 队列剩余大小:5 队列使用度:50.00%
pool-1-thread-16-创建任务-: 核心线程数:10 活动线程数:10 最大线程数:10 线程池活跃度:100.00% 任务完成数:0 队列大小:10 当前排队线程数:5 队列剩余大小:5 队列使用度:50.00%
pool-1-thread-1-创建任务-: 核心线程数:10 活动线程数:10 最大线程数:10 线程池活跃度:100.00% 任务完成数:4 队列大小:10 当前排队线程数:1 队列剩余大小:9 队列使用度:10.00%
pool-1-thread-5-创建任务-: 核心线程数:10 活动线程数:10 最大线程数:10 线程池活跃度:100.00% 任务完成数:4 队列大小:10 当前排队线程数:1 队列剩余大小:9 队列使用度:10.00%
pool-1-thread-2-创建任务-: 核心线程数:10 活动线程数:10 最大线程数:10 线程池活跃度:100.00% 任务完成数:4 队列大小:10 当前排队线程数:1 队列剩余大小:9 队列使用度:10.00%
pool-1-thread-3-创建任务-: 核心线程数:10 活动线程数:10 最大线程数:10 线程池活跃度:100.00% 任务完成数:4 队列大小:10 当前排队线程数:1 队列剩余大小:9 队列使用度:10.00%
pool-1-thread-4-创建任务-: 核心线程数:10 活动线程数:10 最大线程数:10 线程池活跃度:100.00% 任务完成数:5 队列大小:10 当前排队线程数:0 队列剩余大小:10 队列使用度:0.00%

Process finished with exit code 1

setCorePoolSize()源码

    /**
     * Sets the core number of threads.  This overrides any value set
     * in the constructor. If the new value is smaller than the
     * current value, excess existing threads will be terminated when
     * they next become idle.  If larger, new threads will, if needed,
     * be started to execute any queued tasks.
     *
     * @param corePoolSize the new core size
     * @throws IllegalArgumentException if {@code corePoolSize < 0}
     * @see #getCorePoolSize
     */
    public void setCorePoolSize(int corePoolSize) {
        if (corePoolSize < 0)
            throw new IllegalArgumentException();
        int delta = corePoolSize - this.corePoolSize;
        this.corePoolSize = corePoolSize;
        if (workerCountOf(ctl.get()) > corePoolSize)
            interruptIdleWorkers();
        else if (delta > 0) {
            // We don't really know how many new threads are "needed".
            // As a heuristic, prestart enough new workers (up to new
            // core size) to handle the current number of tasks in
            // queue, but stop if queue becomes empty while doing so.
            int k = Math.min(delta, workQueue.size());
            while (k-- > 0 && addWorker(null, true)) {
                if (workQueue.isEmpty())
                    break;
            }
        }
    }

在运行期线程池使用方调用此方法设置corePoolSize之后,线程池会直接覆盖原来的corePoolSize值,并且基于当前值和原始值的比较结果采取不同的处理策略。

对于最新的核心线程数小于当前工作线程数的情况,说明有多余的worker线程,此时会向当前idle的worker线程发起中断请求以实现回收,多余的worker在下次idel的时候也会被回收;

当最新的核心线程数大于之前核心线程数时,不是一致性增加差额的线程数,而是一个一个线程创建,创建完一个再去查询任务队列是否有任务;有任务则再次创建新的worker线程来执行队列任务,没有任务则就此停止,setCorePoolSize具体流程如下:
1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值