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. 在Spring的事务体系中,事务传播特性:Required和RequiresNew有何不同?

    Required 如果当前存在一个事务,则加入当前事务.如果不存在任何事务,则创建一个新的事务.总之,要至少保证在一个事务中运行.PROPAGATION_REQUIRED通常作为默认的事务传播行为.p ...

  2. Gradle 使用@Value注册编译报错

    报错信息:Expected '$(student - name)' to be an inline constant of type java.lang.String in @org.springfr ...

  3. javax.net.ssl.sslhandshakeException:sun.security.validator.validatorException:PKIX path buildind failed

    前段时间开发的一个需求,需要通过图片URL获取图片的base64编码,测试的时候使用的是百度图片的url,测试没有问题,但是发布后测试时报如下错: javax.net.ssl.sslhandshake ...

  4. mac-变量

    去除每次都要source : 加入:

  5. Redis 常见性能问题和解决方案?

    1.Master 最好不要写内存快照,如果 Master 写内存快照,save 命令调度 rdbSave 函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性 暂停服务 2.如果数据 ...

  6. 是否可以从一个静态(static)方法内部发出对非静态 (non-static)方法的调用?

    不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,在 调用静态方法时可能对象并没有被初始化.

  7. Citus 分布式 PostgreSQL 集群 - SQL Reference(手动查询传播)

    手动查询传播 当用户发出查询时,Citus coordinator 将其划分为更小的查询片段,其中每个查询片段可以在工作分片上独立运行.这允许 Citus 将每个查询分布在集群中. 但是,将查询划分为 ...

  8. k-medoids算法

    k-medoids算法 对上面图形的解释 第一幅图:原来p属于Oj的(实线),当Orandom代替了Oj,p属于Oi了(虚线):第二幅图:原来p属于Oj的(实线),当Orandom代替了Oj,p属于O ...

  9. stm32CubeMX+keil5好用还是stm32CubeID好用

    cubemx是图形配置软件, 可以节省往常配置IO口的时间, cubemx主推hal库, 它是生成keil工程的工具 cubemx生成的工程可以用keilv5编程软件来编辑... 用Cube mx定义 ...

  10. video元素和audio元素相关事件

    前言 在利用video元素或audio元素读取或播放媒体数据时,会触发一系列事件,如果用js脚本来捕抓这些事件,就可以对着这些事件进行处理了. 捕抓的方式有两种: 第一种是监听的方式.使用vedio或 ...