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. Java常用类笔记(学习尚硅谷java基础教程)

    一.Java根类Object类1.toString()方法 1)以文本对象返回,故toString()的定义为public String toString() {} 2)默认的字符串输出是:包.类名@ ...

  2. 你也可以很硬核「GitHub 热点速览 v.22.13」

    本周特推介绍了一个非常易上手,操作难度(主要难度在于机件购买)极低的硬件项目,SmartKnob 让你有个可玩性极高的控制仪.本周特推另外一个项目则是一个安全项目,打破你对 URL 是可靠.安全的认知 ...

  3. requests库获取图片响应流进行转发

    遇到了一个问题,使用requests进行转发 requests响应流的时候,出现各种问题,问题的描述没有记录,不过Debug以下终于解决了问题.......下面简单的描述解决方案 response = ...

  4. 为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动 的区别在哪里?

    Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联 集合对象时,可以根据对象关系模型直接获取,所以它是全自动的.而 Mybatis 在查询关联对象或关联集 ...

  5. jQuery--筛选【串联函数】

    串联函数简介 A.add(B) 将A和B组合成一个对象 A.children().andSelf() 将之前的对象添加到操作集合中 A.children().children().end() 回到最近 ...

  6. springboot-数据库访问之jpa

    什么是springDate? springData的作用: 整体简化的架构: JPA :Java Persistence API 如果没有springData 我们需要去学每一种对应的jpa实现, 有 ...

  7. 去掉win10的命令行

    FluentTerminal 和xshell类似,多个终端在一个页面,比较舒服,可复制,可粘贴 界面: https://github.com/felixse/FluentTerminal 自己去git ...

  8. 请用c++ 实现stl中的string类,实现构造,拷贝构造,析构,赋值,比较,字符串相加,获取长度及子串等功能。

    1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 class String{ 5 public ...

  9. mysql 的INNODB引擎和MYISAM引擎的区别、索引相关

    两个引擎都是使用B+tree 数据结构作为索引 不同点: 1.INNODB的主键必须要有,同时也是聚集索引,INNODB的数据文件本身就是索引文件:而MYISAM则是存储了数据的地址 2.INNODB ...

  10. 如何更愉快地使用em —— 别说你懂CSS相对单位

    前段时间试译了Keith J.Grant的CSS好书<CSS in Depth>,其中的第二章<Working with relative units>,书中对relative ...