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 线程池四种拒绝策略的更多相关文章

  1. Java 线程池 8 大拒绝策略,面试必问!

    前言 谈到java的线程池最熟悉的莫过于ExecutorService接口了,jdk1.5新增的java.util.concurrent包下的这个api,大大的简化了多线程代码的开发.而不论你用Fix ...

  2. Java-五种线程池,四种拒绝策略,三种阻塞队列(转)

    Java-五种线程池,四种拒绝策略,三种阻塞队列 三种阻塞队列:    BlockingQueue<Runnable> workQueue = null;    workQueue = n ...

  3. JUC之线程池-三大方法-七大参数-四种拒绝策略

    线程池:重点 三大方法 七大参数 四种拒绝策略 使用池化技术的理由: 我们的程序伴随着创建销毁线程十分浪费资源, 所以使用线程池,先创建线程,随用随取,用完归还 简单来说就是节约了资源. 使用线程池的 ...

  4. windows线程池四种情形(win核心读书笔记)

    windows线程池四种情形(win核心读书笔记) Mircosoft从Windows2000引入线程池API,并在Vista后对线程池重新构架,引入新的线程池API.以下所有线程池函数均适用于Vis ...

  5. Java线程池底层源码分享和相关面试题(持续更新)

    线程池各个参数讲解 public ThreadPoolExecutor(int corePoolSize, //线程池核心工作线程数量,比如newFixedThreadPool中可以自定义的线程数量就 ...

  6. 《Java线程池》:任务拒绝策略

    在没有分析线程池原理之前先来分析下为什么有任务拒绝的情况发生. 这里先假设一个前提:线程池有一个任务队列,用于缓存所有待处理的任务,正在处理的任务将从任务队列中移除.因此在任务队列长度有限的情况下就会 ...

  7. Java线程池的拒绝策略

    一.简介 jdk1.5 版本新增了JUC并发编程包,极大的简化了传统的多线程开发.前面文章中介绍了线程池的使用,链接地址:https://www.cnblogs.com/eric-fang/p/900 ...

  8. Java 线程池框架核心代码分析--转

    原文地址:http://www.codeceo.com/article/java-thread-pool-kernal.html 前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和 ...

  9. Java 线程池框架核心代码分析

    前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和资源消耗都是很高的.线程池应运而生,成为我们管理线程的利器.Java 通过Executor接口,提供了一种标准的方法将任务的提交过 ...

随机推荐

  1. 【推理引擎】从源码看ONNXRuntime的执行流程

    目录 前言 准备工作 构造 InferenceSession 对象 & 初始化 让模型 Run 总结 前言 在上一篇博客中:[推理引擎]ONNXRuntime 的架构设计,主要从文档上对ONN ...

  2. String是基本数据类型吗?

    基本数据类型包括byte.short.int.long.char.float.double和boolean.String不是基本类型.String是引用类型. 而且java.lang.String类是 ...

  3. BIO、NIO、AIO 有什么区别?

    BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低.NIO:New IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 ...

  4. select poll和epoll

    select poll epoll都是IO多路复用机制.这里的复用其实可以理解为复用的线程,即一个(或者较少的)线程完成多个IO的读写.这里总结下这三个函数的区别. 1 select 1.1 sele ...

  5. 阐述 final、finally、finalize 的区别?

    final:修饰符(关键字)有三种用法:如果一个类被声明为 final,意味 着它不能再派生出新的子类,即不能被继承,因此它和 abstract 是反义词.将 变量声明为 final,可以保证它们在使 ...

  6. Spring ModelAttribute注解失效原因

    public String test(@RequestParam(value = "test") @ModelAttribute("test") String ...

  7. carsim笔记——道路设置

    第一步: 进入道路轨迹设置 道路情况设置举例 第二步:设置道路3D的显示效果 对上面的解释举例说明

  8. 使用jquery-webcam插件,实现人脸采集并转base64

    项目需求:在ie或chrome浏览器下,调用电脑摄像头(确保使用的是笔记本电脑,或者摄像头功能正常使用的台式机),进行人脸图像采集预览,并将图片的base64码传入到后台进行后续操作.该demo适用于 ...

  9. Python窗口学习之搜索框美化

    初学tkinter,感觉这个插件虽然是做界面的,但是没有html,也没有android那么人性化 既没有画圆角长方形的办法也没有添加透明按钮的办法(可能是我没找到) 所以自己用canvas画了两个扇形 ...

  10. css3 calc浏览器中显示Invalid propety value

    在写前端页面样式中使用calc 显示Invalid property value 后来查了文档之后才发现是自己的格式不对 我的写法: .clac { width:calc(100%-112px); } ...