理解线程池中七大核心参数,四大拒绝策略有什么作用?

线程池参数配置

直接上代码

 public ThreadPoolExecutor(int corePoolSize, //核心线程数
                              int maximumPoolSize,//最大核心线程数
                              long keepAliveTime,//超时时间
                              TimeUnit unit,//超时时间单位
                              BlockingQueue<Runnable> workQueue,//阻塞队列
                              ThreadFactory threadFactory,//线程池工厂
                              RejectedExecutionHandler handler)//拒绝策略

上图演示
理解线程池中七大核心参数,四大拒绝策略有什么作用?
如上图所示, 窗口1、窗口2就是我们的核心线程数, 窗口3、窗口4、窗口5就是我们的最大核心线程数,候车1、候车2、候车3表示我们的阻塞队列

下面进入代码测试,自己配置线程池参数corePoolSize=2,maximumPoolSize=3,LinkedBlockingDeque=2,AbortPolicy拒绝策略

public class MyThreadDemo {

    public static void main(String[] args) {

        ExecutorService threadPool = new ThreadPoolExecutor(
                2,//corePoolSize
                3,//maximumPoolSize
                3,//keepAliveTime
                TimeUnit.SECONDS,//TimeUnit unit
                new LinkedBlockingDeque(3),//BlockingQueue<Runnable> workQueue
                Executors.defaultThreadFactory(),//ThreadFactory threadFactory
                new ThreadPoolExecutor.AbortPolicy() //RejectedExecutionHandler handler
        );

        try {

            for (int i = 0; i < 6; i++) {
	            //之前都是手动自己new线程,效率不高 new Thread(()->{sout(); }).start();
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"开始执行");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

corePoolSize 就是一开始当你提交任务的时候就先帮你创建好线程的个数
LinkedBlockingDeque 阻塞队列就是当你提交的任务数大于corePoolSize个数,会临时帮你放在这里,就相当于上面的候车区一样等待执行,但是此时线程个数还是在corePoolSize配置的范围之内,不会开启第三个线程,

如果我把上面的for循环改成 i<2 ,结果如下所示

pool-1-thread-2开始执行
pool-1-thread-1开始执行

这个时候你提交的任务数其实是<=corePoolSize,核心线程个数是完全够用的,不用开辟第三个线程执行,所以只会存在thread-1,thread-2

如果我把上面的for循环改成 i<3 ,结果如下所示

pool-1-thread-2开始执行
pool-1-thread-1开始执行

你会发现结果还是一样的,只会存在两个线程执行任务,虽然你提交的任务数大于了corePoolSize个数, 但是因为这里的阻塞队列将你的第三个提交的任务给缓存起来了,等待两个线程中的其中一个执行完就会开始从阻塞队列中获取任务进行执行,所以这里也不用开启第三个线程执行

那什么时候回开启第3个线程执行呢?

当我们的这个提交的任务数>corePoolSize 个数+LinkedBlockingDeque 个数时,就会开启第三个线程执行,这里我们把for循环里的值改成6,这个时候就会开启我们的maximumPoolSize配置的线程,因阻塞队列最大就只能给你缓存三个任务数,然后corePoolSize 个人也只最多处理2个任务请求,所以不得不扩张资源,所以得把线程3给开启执行任务,所以这里一共就会有3个线程开始执行任务了,结果如下所示:

pool-1-thread-1开始执行
pool-1-thread-2开始执行
pool-1-thread-3开始执行
pool-1-thread-1开始执行
pool-1-thread-3开始执行
pool-1-thread-2开始执行

但是这里你要注意,如果你把for循环里的值设置超过了6,这个时候因为最多撑死就只能够同时执行个任务,所以这里会抛出拒绝策略,拒绝策略默认是直接抛出异常,我这里在for循环设置成7,结果如下图所示:

pool-1-thread-1开始执行
pool-1-thread-3开始执行
pool-1-thread-2开始执行
pool-1-thread-3开始执行
pool-1-thread-1开始执行
pool-1-thread-2开始执行
java.util.concurrent.RejectedExecutionException: Task com.cn.MyThreadDemo$$Lambda$1/1023892928@7699a589 rejected from java.util.concurrent.ThreadPoolExecutor@58372a00[Running, pool size = 3, active threads = 3, queued tasks = 1, completed tasks = 2]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
	at com.cn.MyThreadDemo.main(MyThreadDemo.java:21)

上述代码直接copy到本地方便在忘记了直接验证就可以

 

拒绝策略

这里我们再简单补充一下4中拒绝策略

上一篇:Java线程池ThreadPoolExecutor源码浅析


下一篇:Java线程池相关知识