Java线程池的拒绝策略
一、简介
jdk1.5 版本新增了JUC并发编程包,极大的简化了传统的多线程开发。前面文章中介绍了线程池的使用,链接地址:https://www.cnblogs.com/eric-fang/p/9004020.html
Java线程池,是典型的池化思想的产物,类似的还有数据库的连接池、redis的连接池等。池化思想,就是在初始的时候去申请资源,创建一批可使用的连接,这样在使用的时候,就不必再进行创建连接信息的开销了。举个生活中鲜明的例子,在去著名洋快餐某基或者某劳的时候,配餐人员是从一个中间的保温箱中直接取食材,然后打包就好了。不用再临时的来了一个单子,又要去拿原材料,又要去进行加工。效率明显的就是提高了很多。
俗话说 满而不损则溢,盈而不持则倾。线程池既然是容器,那么必然的会有存满的情况。在达到某些特定条件的时候,再来请求的话,池子是如何进行请求处理的呢?这里就引出了池的拒绝策略。一般的数据库连接池在达到最大连接数的时候会默认的等待特定的设置的时间或者直接就抛出异常。而本文中要阐述的线程池却并非如此的策略,下面开始展开讲解下。
二、线程池的拒绝策略
线程池中,有三个重要的参数,决定影响了拒绝策略:corePoolSize - 核心线程数,也即最小的线程数。workQueue - 阻塞队列 。 maximumPoolSize - 最大线程数
当提交任务数大于 corePoolSize 的时候,会优先将任务放到 workQueue 阻塞队列中。当阻塞队列饱和后,会扩充线程池中线程数,直到达到 maximumPoolSize 最大线程数配置。此时,再多余的任务,则会触发线程池的拒绝策略了。
总结起来,也就是一句话,当提交的任务数大于(workQueue.size() + maximumPoolSize ),就会触发线程池的拒绝策略。
三、拒绝策略定义
拒绝策略提供顶级接口 RejectedExecutionHandler ,其中方法 rejectedExecution 即定制具体的拒绝策略的执行逻辑。
jdk默认提供了四种拒绝策略:
CallerRunsPolicy - 当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。一般并发比较小,性能要求不高,不允许失败。但是,由于调用者自己运行任务,如果任务提交速度过快,可能导致程序阻塞,性能效率上必然的损失较大
AbortPolicy - 丢弃任务,并抛出拒绝执行 RejectedExecutionException 异常信息。线程池默认的拒绝策略。必须处理好抛出的异常,否则会打断当前的执行流程,影响后续的任务执行。
DiscardPolicy - 直接丢弃,其他啥都没有
DiscardOldestPolicy - 当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入
四、测试代码
1、AbortPolicy
package com.cfang; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; @Slf4j
public class T2 { public static void main(String[] args) throws Exception{
int corePoolSize = ;
int maximumPoolSize = ;
long keepAliveTime = ;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, handler);
for(int i=; i<; i++) {
try {
executor.execute(new Thread(() -> log.info(Thread.currentThread().getName() + " is running")));
} catch (Exception e) {
log.error(e.getMessage());
}
}
executor.shutdown();
}
}
executor.execute()提交任务,由于会抛出 RuntimeException,如果没有try.catch处理异常信息的话,会中断调用者的处理流程,后续任务得不到执行(跑不完100个)。可自行测试下,很容易在控制台console中能查看到。
2、CallerRunsPolicy
主体代码同上,更换拒绝策略:
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
运行后,在控制台console中能够看到的是,会有一部分的数据打印,显示的是 “main is running”,也即体现调用线程处理。
3、DiscardPolicy
更换拒绝策略
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
直接丢弃任务,实际运行中,打印出的信息不会有100条。
4、DiscardOldestPolicy
同样的,更换拒绝策略:
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardOldestPolicy();
实际运行,打印出的信息也会少于100条。
五、总结
四种拒绝策略是相互独立无关的,选择何种策略去执行,还得结合具体的业务场景。实际工作中,一般直接使用 ExecutorService 的时候,都是使用的默认的 defaultHandler ,也即 AbortPolicy 策略。
Java线程池的拒绝策略的更多相关文章
- JDK线程池的拒绝策略
关于新疆服务请求未带入来话原因的问题 经核查,该问题是由于立单接口内部没有成功调用接续的 “更新来电原因接口”导致的,接续测更新来电原因接口编码:NGCCT_UPDATESRFLAG_PUT ,立单接 ...
- SimpleThreadPool给线程池增加拒绝策略和停止方法
给线程池增加拒绝策略和停止方法 package com.dwz.concurrency.chapter13; import java.util.ArrayList; import java.util. ...
- Dubbo里面线程池的拒绝策略
Dubbo里面线程池的拒绝策略 public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy { protecte ...
- dubbo线程池的拒绝策略
jdk自带的原生的拒绝策略抛出的异常信息不够详细,而dubbo对拒绝策略进行了改写,抛出的信息更具有参考价值,值得我们借鉴. jdk自带的原生拒绝策略抛出的信息: // ThreadPoolExecu ...
- Java - "JUC线程池" 线程状态与拒绝策略源码分析
Java多线程系列--“JUC线程池”04之 线程池原理(三) 本章介绍线程池的生命周期.在"Java多线程系列--“基础篇”01之 基本概念"中,我们介绍过,线程有5种状态:新建 ...
- Java 线程池 8 大拒绝策略,面试必问!
前言 谈到java的线程池最熟悉的莫过于ExecutorService接口了,jdk1.5新增的java.util.concurrent包下的这个api,大大的简化了多线程代码的开发.而不论你用Fix ...
- java并发:线程池、饱和策略、定制、扩展
一.序言 当我们需要使用线程的时候,我们可以新建一个线程,然后显式调用线程的start()方法,这样实现起来非常简便,但在某些场景下存在缺陷:如果需要同时执行多个任务(即并发的线程数量很多),频繁地创 ...
- 面试题-关于Java线程池一篇文章就够了
在Java面试中,线程池相关知识,虽不能说是必问提,但出现的频次也是非常高的.同时又鉴于公众号"程序新视界"的读者后台留言让写一篇关于Java线程池的文章,于是就有本篇内容,本篇将 ...
- JUC(4)---java线程池原理及源码分析
线程池,既然是个池子里面肯定就装很多线程. 如果并发的请求数量非常多,但每个线程执行的时间很短,这样就会频繁的创建和销毁 线程,如此一来会大大降低系统的效率.可能出现服务器在为每个请求创建新线程和销毁 ...
随机推荐
- Protocol, Delegate
协议的构成: 协议:用来指定代理双方可以做什么,必须做什么. 代理:根据指定的协议,完成委托方需要实现的功能. 委托:根据指定的协议,指定代理去完成什么功能. 协议的修饰符: 协议有两个修饰符@opt ...
- Mybatis批处理(批量查询,更新,插入)
mybatis批量查询 注意这里的 in 和 <trim prefix="(" suffix=")"> 以及 in ( )的三种方式的(例1(推 ...
- js如何使用radio
<input name="sex" type="radio" value="男" checked="checked" ...
- 一文了解Python常见的序列化操作
关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...
- Java IO体系之File类浅析
Java IO体系之File类浅析 一.File类介绍 位于java.io下的Java File类以抽象的方式代表文件名和目录路径名.该类主要用于文件和目录的创建.文件的查找和文件的删除等.File对 ...
- 《阿里巴巴Java开发手册1.4.0》阅读总结与心得(三)
(六)工程结构 (一)应用分层 1. [推荐]图中默认上层依赖于下层,箭头关系表示可直接依赖,如:开放接口层可以依赖于Web 层,也可以直接依赖于 Service 层,依此类推: 开放接口层: ...
- 【JVM从小白学成大佬】6.创建对象及对象的访问定位
<JVM从小白学成大佬>系列推出到现在,收到了很多小伙伴的好评,也收到了一些小伙伴的建议,在此表示感谢. 有几个小伙伴提出了希望出一篇介绍对象的创建及访问,猿人谷向来是没有原则的,小伙们要 ...
- 2019nc#4
题号 标题 已通过代码 题解 通过率 团队的状态 A meeting 点击查看 树直径 604/2055 B xor 点击查看 线段树维护线性基交 81/861 未通过 C sequence 点击 ...
- 计蒜客 蓝桥杯模拟 瞬间移动 dp
在一个 n \times mn×m 中的方格中,每个格子上都有一个分数,现在蒜头君从 (1,1)(1,1) 的格子开始往 (n, m)(n,m) 的格子走.要求从 (x_1,y_1)(x1,y1 ...
- 最短路算法 Dijkstra 入门
dijkstra算法 是一种单源点最短路算法求出一个点到其他所有点的最短路. 给你这样的一个图,需要求出1号点到其他点的最短距离是多少. 首先我们开一个数组 d[N],d[x] 代表着从起点出发到x点 ...