Java线程池的四种拒绝策略详解

网友投稿 359 2022-08-02


目录预先配置配置线程池。创建线程任务拒绝策略一:AbortPolicy拒绝策略二:CallerRunsPolicy拒绝策略三:DiscardPolicy拒绝策略四:DiscardOldestPolicy总结

dk1.5版本新增了 JUC 并发包,其中一个包含线程池。

四种拒绝策略:

拒绝策略类型说明1ThreadPoolExecutor.AbortPolicy默认拒绝策略,拒绝任务并抛出任务2ThreadPoolExecutor.CallerRunsPolicy使用调用线程直接运行任务3ThreadPoolExecutor.DiscardPolicy直接拒绝任务,不抛出错误4ThreadPoolExecutor.DiscardOldestPolicy触发拒绝策略,只要还有任务新增,一直会丢弃阻塞队列的最老的任务,并将新的任务加入

预先配置

配置线程池。

核心线程和最大线程都尽量设置的小一点,分别设置成 1 和 2阻塞队列设置固定长度的有界队列,长度为 1线程工厂设置默认线程工厂

// 核心线程数

int corePoolSize = 1;

// 最大线程数

int maximumPoolSize = 2;

// 线程存活时间

long keepAliveTime = 10;

// 线程存活时间单位

TimeUnit unit = TimeUnit.SECONDS;

// 有界队列 遵循 FIFO 原则

BlockingQueue workQueue = new ArrayBlockingQueue<>(1);

// 线程工厂

ThreadFactory threadFactory = Executors.defaultThreadFactory();

创建线程任务

创建线程任务,一个线程任务执行一秒:

class TaskThread implements Runnable{

private int i;

public TaskThread(int i) {

this.i = i;

}

@Override

public void run() {

try {

TimeUnit.SECONDS.sleep(2);

System.out.println("执行任务:" + i);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

拒绝策略一:AbortPolicy

默认拒绝策略,拒绝任务并抛出任务

// 拒绝策略 默认拒绝策略,拒绝任务并抛出异常:

RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(corePoolSize,

maximumPoolSize,

keepAliveTime,

unit,

workQueue,

threadFactory,

handler);

for (int i = 1; i <= 5; i++) {

try {

threadPool.execute(new TaskThread(i));

} catch (Exception e) {

System.out.println("【任务" + i + "】报错:" + e.getMessage());

}

}

输出

【任务】4报错:Task com.test.controller.ThreadPoolController$TaskThread@5c0369c4 rejected from java.util.concurrent.ThreadPoolExecutor@50675690[Running, pool size = 2, active threads = 2, queued tasks = ChVOGIGam1, completed tasks = 0]【任务】5报错:Task com.test.controller.ThreadPoolController$TaskThread@31b7dea0 rejected from java.util.concurrent.ThreadPoolExecutor@50675690[Running, pool size = 2, active threads = 2, queued tasks = 1, completed tasks = 0]执行任务:1执行任务:3执行任务:2

最大线程数 + 阻塞队列 = 3,执行到4,5的时候就抛出错误。这里需要用 try catch 捕获异常。任务1、2、3正常执行。

如果提交的任务都要执行,可以将抛出的错误任务存入在redis中,然后定时从redis中获取任务,再提交执行。

拒绝策略二:CallerRunsPolicy

调用线程运行多余的任务。

更换拒绝策略,将上面的 AbortPolicy 换成 CallerRunsPolicy。

RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();

执行任务,输出:

执行任务:1执行任务:4执行任务:3执行任务:2执行任务:5

最大线程数 + 阻塞队列 = 3,多余的任务还是继续被执行。

拒绝策略三:DiscardPolicy

拒绝任务,不会抛出错误。更换策略,将CallerRunsPolicy 换成DiscardPolicy:

RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();

执行任务,输出:

执行任务:1执行任务:3执行任务:2

MAKEFILE 复制 全屏

多余的线程任务提交被拒绝,而只执行最大线程数 + 阻塞队列 数量的任务,并且不会抛出错误。

拒绝策略四:DiscardOldestPolicy

只要还有任务新增,一直会丢弃阻塞队列的最老的任务,并将新的任务加入到阻塞队列中。更换策略,将DiscardPolicy 换成DiscardOldestPolicy:

RejectedExecutionHandler handler3 = new ThreadPoolExecutor.DiscardOldestPolicy();

执行任务,输出:

执行任务:3执行任务:1执行任务:5

任务的执行顺序是 核心线程数 —> 阻塞队列 —> 最大线程数,其中任务1,任务3提交成功。

任务2因为在阻塞队列中,后面的任务4把任务2挤掉,任务5又把任务4挤掉,所以最后执行的是任务5。

总结

本文介绍了线程四种拒绝策略,当工作任务大于最大线程 + 阻塞队列会执行阻塞队列。

AbortPolicy 默认策略,拒绝任务,并抛出异常CallerRunsPolicy 调用线程执行对于的任务DiscardPolicy 拒绝任务,不会抛出异常DiscardOldestPolicy 有多余的任务,把阻塞队列最老的任务丢弃,放入新的任务,直到没有新的任务。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:详细分析JVM类加载机制(jvm类加载过程)
下一篇:Java由浅入深细数数组的操作下
相关文章

 发表评论

暂时没有评论,来抢沙发吧~