Java 线程池四种拒绝策略
jdk1.5版本新增了
JUC
并发包,其中一个包含线程池。
四种拒绝策略:
拒绝策略类型 | 说明 | |
---|---|---|
1 | ThreadPoolExecutor.AbortPolicy | 默认拒绝策略,拒绝任务并抛出任务 |
2 | ThreadPoolExecutor.CallerRunsPolicy | 使用调用线程直接运行任务 |
3 | ThreadPoolExecutor.DiscardPolicy | 直接拒绝任务,不抛出错误 |
4 | ThreadPoolExecutor.DiscardOldestPolicy | 触发拒绝策略,只要还有任务新增,一直会丢弃阻塞队列的最老的任务,并将新的任务加入 |
预先配置
配置线程池。
- 核心线程和最大线程都尽量设置的小一点,分别设置成 1 和 2
- 阻塞队列设置固定长度的有界队列,长度为 1
- 线程工厂设置默认线程工厂
// 核心线程数
int corePoolSize = 1;
// 最大线程数
int maximumPoolSize = 2;
// 线程存活时间
long keepAliveTime = 10;
// 线程存活时间单位
TimeUnit unit = TimeUnit.SECONDS;
// 有界队列 遵循 FIFO 原则
BlockingQueue<Runnable> 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 = 1, 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
多余的线程任务提交被拒绝,而只执行最大线程数 + 阻塞队列 数量的任务,并且不会抛出错误。
拒绝策略四:DiscardOldestPolicy
只要还有任务新增,一直会丢弃阻塞队列的最老的任务,并将新的任务加入到阻塞队列中。
更换策略,将DiscardPolicy
换成DiscardOldestPolicy
:
RejectedExecutionHandler handler3 = new ThreadPoolExecutor.DiscardOldestPolicy();
执行任务,输出:
执行任务:3
执行任务:1
执行任务:5
任务的执行顺序是 核心线程数 —> 阻塞队列 —> 最大线程数,其中任务1,任务3提交成功。
- 任务2因为在阻塞队列中,
- 后面的任务4把任务2挤掉,
- 任务5又把任务4挤掉,所以最后执行的是任务5。
总结
本文介绍了线程四种拒绝策略,当工作任务大于最大线程 + 阻塞队列会执行阻塞队列。
- AbortPolicy 默认策略,拒绝任务,并抛出异常
- CallerRunsPolicy 调用线程执行对于的任务
- DiscardPolicy 拒绝任务,不会抛出异常
- DiscardOldestPolicy 有多余的任务,把阻塞队列最老的任务丢弃,放入新的任务,直到没有新的任务。
如果觉得文章对你有帮助的话,请点个推荐吧!
Java 线程池四种拒绝策略的更多相关文章
- Java 线程池 8 大拒绝策略,面试必问!
前言 谈到java的线程池最熟悉的莫过于ExecutorService接口了,jdk1.5新增的java.util.concurrent包下的这个api,大大的简化了多线程代码的开发.而不论你用Fix ...
- Java-五种线程池,四种拒绝策略,三种阻塞队列(转)
Java-五种线程池,四种拒绝策略,三种阻塞队列 三种阻塞队列: BlockingQueue<Runnable> workQueue = null; workQueue = n ...
- JUC之线程池-三大方法-七大参数-四种拒绝策略
线程池:重点 三大方法 七大参数 四种拒绝策略 使用池化技术的理由: 我们的程序伴随着创建销毁线程十分浪费资源, 所以使用线程池,先创建线程,随用随取,用完归还 简单来说就是节约了资源. 使用线程池的 ...
- windows线程池四种情形(win核心读书笔记)
windows线程池四种情形(win核心读书笔记) Mircosoft从Windows2000引入线程池API,并在Vista后对线程池重新构架,引入新的线程池API.以下所有线程池函数均适用于Vis ...
- Java线程池底层源码分享和相关面试题(持续更新)
线程池各个参数讲解 public ThreadPoolExecutor(int corePoolSize, //线程池核心工作线程数量,比如newFixedThreadPool中可以自定义的线程数量就 ...
- 《Java线程池》:任务拒绝策略
在没有分析线程池原理之前先来分析下为什么有任务拒绝的情况发生. 这里先假设一个前提:线程池有一个任务队列,用于缓存所有待处理的任务,正在处理的任务将从任务队列中移除.因此在任务队列长度有限的情况下就会 ...
- Java线程池的拒绝策略
一.简介 jdk1.5 版本新增了JUC并发编程包,极大的简化了传统的多线程开发.前面文章中介绍了线程池的使用,链接地址:https://www.cnblogs.com/eric-fang/p/900 ...
- Java 线程池框架核心代码分析--转
原文地址:http://www.codeceo.com/article/java-thread-pool-kernal.html 前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和 ...
- Java 线程池框架核心代码分析
前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和资源消耗都是很高的.线程池应运而生,成为我们管理线程的利器.Java 通过Executor接口,提供了一种标准的方法将任务的提交过 ...
随机推荐
- leedCode
https://blog.csdn.net/code_yilia/category_9851007.html https://blog.csdn.net/qq_17550379/article/det ...
- SpringCloud和Dubbo?
SpringCloud和Dubbo都是现在主流的微服务架构SpringCloud是Apache旗下的Spring体系下的微服务解决方案Dubbo是阿里系的分布式服务治理框架从技术维度上,其实Sprin ...
- python 列表list-增删改查操作
初始化: a. data_list1 = [] b. data_list2 = [a,b,c] c. data_list = list() 新增: a. data_list1.ap ...
- mq 的缺点 ?
系统可用性降低 系统引入的外部依赖越多,越容易挂掉,本来你就是 A 系统调用 BCD 三个系统的 接口就好了,人 ABCD 四个系统好好的,没啥问题,你偏加个 MQ 进来,万一 MQ 挂了咋整?MQ ...
- spring-boot-learning自动配置原理
启动器: spring-boot-starter:spring-boot场景启动器,帮我们倒入我们场景需要的组件依赖 不同的场景有不同的启动器: spring-boot-starter-web ...
- linux java7升级到java8
转自:https://blog.csdn.net/u010199866/article/details/81744382 linux java7升级到java8 版权 1.第一步先卸载所有老的jd ...
- HTML5存储方式
由于之前在参加面试或者笔试的过程中经常会被问到HTML5存储的内容,包括它们之间的区别.特征和应用范围,所以看到一篇介绍不错的文章,把里面的个人觉得适合我的内容按照自己的理解总结如下.方便以后忘记了进 ...
- Python窗口学习之监听窗口变化触发函数
在窗口大小发生变化后,往往组件也需要调整 代码: #空间适应屏幕 def window_resiz(self,event=None): print(window.winfo_height()) pri ...
- js select 删除某一项下拉列表的值
<script type="text/javascript"> //muqingwei modify 通过群组类别选择需要的的群组 var mySelect = doc ...
- Python实现简单用户注册信息管理系统
运行效果: 注意:运行前请在同一目录下创建一个userdata.bin用于保存用户数据 源代码: 1 # coding:utf-8 2 ''' 3 用户注册信息管理系统 4 功能包括: 5 1.查看全 ...