理解线程池中七⼤核⼼参数,四⼤拒绝策略有什么作⽤?
配置线程池参数
代码演⽰
public ThreadPoolExecutor(int corePoolSize,//核⼼线程数
int maximumPoolSize,//最⼤核⼼线程数
long keepAliveTime,//超时时间
TimeUnit unit,//超时时间单位
BlockingQueue<Runnable> workQueue,//阻塞队列
ThreadFactory threadFactory,//线程池⼯⼚
RejectedExecutionHandler handler)//拒绝策略
图形演⽰
如上图所⽰, 窗⼝1、窗⼝2就是我们的核⼼线程数corePoolSize, 窗⼝3、窗⼝4、窗⼝5就是我们的可扩容的最⼤核⼼线程数maximumPoolSize,候车1、候车2、候车3表⽰我们的阻塞队列
下⾯进⼊代码测试,⾃⼰配置线程池参数:
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(2),//BlockingQueue<Runnable> workQueue
Executors.defaultThreadFactory(),//ThreadFactory threadFactory
new ThreadPoolExecutor.AbortPolicy()//RejectedExecutionHandler handler
);
try{
for(int i =0; i <5; i++){
/
/之前都是⼿动⾃⼰new线程,效率不⾼ new Thread(()->{sout(); }).start();
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<4 ,结果如下所⽰
pool-1-thread-2开始执⾏
pool-1-thread-1开始执⾏
你会发现结果还是⼀样的,只会开启两个线程执⾏任务,虽然你提交的任务数⼤于了corePoolSize个数, 但是因为这⾥的阻塞队列将你的第三个、第三个提交的任务给缓存起来了,等待两个线程中的其中⼀个执⾏完就会开始从阻塞队列中获取任务进⾏执⾏,所以这⾥也不⽤开启第三个线程执⾏
那什么时候回开启第3个线程执⾏呢?
当我们的这个提交的任务数>corePoolSize个数+LinkedBlockingDeque个数时,也就是corePoolSize 满了,LinkedBlockingDeque也满了,就会开启第3个线程执⾏,这⾥我们把for循环⾥的值改成5,这个时候就会开启我们的maximumPoolSize配置的线程,因阻塞队列最⼤就只能给你缓存2个任务数,然后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循环⾥的值设置超过了5,因为这⾥我们最多就只能开=maximumPoolSize+LinkedBlockingDequed个,也就是5个,这个时候因为最多撑死就只能够同时执⾏5个任务,所以这⾥会抛出拒绝策略,拒绝策略默认是直接抛出异常,我这⾥在for循环设置成6,结果如下图所⽰:
pool-1-thread-2开始执⾏
pool-1-thread-2开始执⾏
pool-1-thread-2开始执⾏
java线程池创建的四种pool-1-thread-3开始执⾏
pool-1-thread-1开始执⾏
urrent.RejectedExecutionException: Task com.MyThreadDemo$$Lambda$1/102389
2928@7699a589 rejected from urrent.Th readPoolExecutor@58372a00[Running, pool size =3, active threads =2, queued tasks =0, completed tasks =3]
at urrent.jectedExecution(ThreadPoolExecutor.java:2063)
at ject(ThreadPoolExecutor.java:830)
at ute(ThreadPoolExecutor.java:1379)
at com.MyThreadDemo.main(MyThreadDemo.java:21)
上述代码⽅便演⽰,所以配置的参数也是不合理的,真是场景需要根据业务场景⾃⼰估计,代码可以直接copy到本地⽅便直接验证
拒绝策略
这⾥我们再简单补充⼀下4中拒绝策略,什么时候抛出处呢?
当我们的最⼤线程数满了+阻塞队列也满了
AbortPolicy(默认策略)
把上述代码拿来验证下,以下是四种策略运⾏结果:
ExecutorService threadPool =new ThreadPoolExecutor(
3,5,3,TimeUnit.SECONDS,
new LinkedBlockingDeque(2),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
这⾥我们配置默认AbortPolicy策略运⾏结果如下所⽰,直接抛出了异常信息
pool-1-thread-2开始执⾏
pool-1-thread-3开始执⾏
pool-1-thread-1开始执⾏
pool-1-thread-3开始执⾏
pool-1-thread-2开始执⾏
urrent.RejectedExecutionException: Task com.MyThreadDemo$$Lambda$1/1023892928@7699a589 rejected from urrent.Th readPoolExecutor@58372a00[Running, pool size =3, active threads =2, queued tasks =0, completed tasks =2]
at urrent.jectedExecution(ThreadPoolExecutor.java:2063)
at ject(ThreadPoolExecutor.java:830)
at ute(ThreadPoolExecutor.java:1379)
at com.MyThreadDemo.main(MyThreadDemo.java:21)
CallerRunsPolicy 策略
我们发现最后⼀个任务竟然还是main线程帮我们执⾏了,因为CallerRunsPolicy策略就是,等线程池处理不了的任务,谁提交的任务,就给谁拿回去,让她⾃⼰执⾏,这⾥发现是main提交的任务,所以最终还是还给了main线程⾃⼰执⾏
main开始执⾏
pool-1-thread-1开始执⾏
pool-1-thread-3开始执⾏
pool-1-thread-2开始执⾏
pool-1-thread-3开始执⾏
pool-1-thread-1开始执⾏
DiscardPolicy 策略
直接抛弃策略,异常也不会抛,什么都不做
pool-1-thread-2开始执⾏
pool-1-thread-3开始执⾏
pool-1-thread-1开始执⾏
pool-1-thread-3开始执⾏
pool-1-thread-2开始执⾏
DiscardOldestPolicy 策略
尝试第⼀个线程帮忙执⾏,但是得要等线程1给执⾏完才可以执⾏,不过这个得在线程配置⼤⼀点情况下才可以看出,这⾥我也是试了很久感觉没啥效果
pool-1-thread-1开始执⾏
pool-1-thread-3开始执⾏
pool-1-thread-2开始执⾏
pool-1-thread-3开始执⾏
pool-1-thread-1开始执⾏
不过当你配置抛弃策略为什么都不做的话,这样很难发现定位你的问题,所以最好不要⽤这种抛弃策略
⼀般线程中最⼤线程池参数配置多⼤呢?
CPU密集型:查看你的cpu核⼼是⼏核数,这个最⼤线程池就是配置成⼏
IO密集型: 当你发现你的5个IO执⾏效率很慢,这个时候你可以开2倍最⼤核核⼼线程数,5个处理你的IO效率慢的,还剩下5个处理后⾯提交的任务,这样不⾄于阻塞你的后续线程任务
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论