java中有界队列的饱和策略(reject policy)
文章目录
- AbortPolicy
- DiscardPolicy
- DiscardOldestPolicy
- CallerRunsPolicy
- 使用Semaphore
java中有界队列的饱和策略(reject policy)
我们在使用ExecutorService的时候知道,在ExecutorService中有个一个Queue来保存提交的任务,通过不同的构造函数,我们可以创建无界的队列(ExecutorService.newCachedThreadPool)和有界的队列(ExecutorService newFixedThreadPool(int nThreads))。
无界队列很好理解,我们可以无限制的向ExecutorService提交任务。那么对于有界队列来说,如果队列满了该怎么处理呢?
今天我们要介绍一下java中ExecutorService的饱和策略(reject policy)。
以ExecutorService的具体实现ThreadPoolExecutor来说,它定义了4种饱和策略。分别是AbortPolicy,DiscardPolicy,DiscardOldestPolicy和CallerRunsPolicy。
如果要在ThreadPoolExecutor中设定饱和策略可以调用setRejectedExecutionHandler方法,如下所示:
ThreadPoolExecutor threadPoolExecutor= new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(20));threadPoolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
上面的例子中我们定义了一个初始5个,最大10个工作线程的Thread Pool,并且定义其中的Queue的容量是20。如果提交的任务超出了容量,则会使用AbortPolicy策略。
AbortPolicy
AbortPolicy意思是如果队列满了,最新的提交任务将会被拒绝,并抛出RejectedExecutionException异常:
public static class AbortPolicy implements RejectedExecutionHandler {/*** Creates an {@code AbortPolicy}.*/public AbortPolicy() { }/*** Always throws RejectedExecutionException.** @param r the runnable task requested to be executed* @param e the executor attempting to execute this task* @throws RejectedExecutionException always*/public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {throw new RejectedExecutionException("Task " + r.toString() +" rejected from " +e.toString());}}
上面的代码中,rejectedExecution方法中我们直接抛出了RejectedExecutionException异常。
DiscardPolicy
DiscardPolicy将会悄悄的丢弃提交的任务,而不报任何异常。
public static class DiscardPolicy implements RejectedExecutionHandler {/*** Creates a {@code DiscardPolicy}.*/public DiscardPolicy() { }/*** Does nothing, which has the effect of discarding task r.** @param r the runnable task requested to be executed* @param e the executor attempting to execute this task*/public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {}}
DiscardOldestPolicy
DiscardOldestPolicy将会丢弃最老的任务,保存最新插入的任务。
public static class DiscardOldestPolicy implements RejectedExecutionHandler {/*** Creates a {@code DiscardOldestPolicy} for the given executor.*/public DiscardOldestPolicy() { }/*** Obtains and ignores the next task that the executor* would otherwise execute, if one is immediately available,* and then retries execution of task r, unless the executor* is shut down, in which case task r is instead discarded.** @param r the runnable task requested to be executed* @param e the executor attempting to execute this task*/public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {if (!e.isShutdown()) {e.getQueue().poll();e.execute(r);}}}
我们看到在rejectedExecution方法中,poll了最老的一个任务,然后使用ThreadPoolExecutor提交了一个最新的任务。
CallerRunsPolicy
CallerRunsPolicy和其他的几个策略不同,它既不会抛弃任务,也不会抛出异常,而是将任务回退给调用者,使用调用者的线程来执行任务,从而降低调用者的调用速度。我们看下是怎么实现的:
public static class CallerRunsPolicy implements RejectedExecutionHandler {/*** Creates a {@code CallerRunsPolicy}.*/public CallerRunsPolicy() { }/*** Executes task r in the caller's thread, unless the executor* has been shut down, in which case the task is discarded.** @param r the runnable task requested to be executed* @param e the executor attempting to execute this task*/public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {if (!e.isShutdown()) {r.run();}}}
在rejectedExecution方法中,直接调用了 r.run()方法,这会导致该方法直接在调用者的主线程中执行,而不是在线程池中执行。从而导致主线程在该任务执行结束之前不能提交任何任务。从而有效的阻止了任务的提交。
使用Semaphore
如果我们并没有定义饱和策略,那么有没有什么方法来控制任务的提交速度呢?考虑下之前我们讲到的Semaphore,我们可以指定一定的资源信号量来控制任务的提交,如下所示:
public class SemaphoreUsage {private final Executor executor;private final Semaphore semaphore;public SemaphoreUsage(Executor executor, int count) {this.executor = executor;this.semaphore = new Semaphore(count);}public void submitTask(final Runnable command) throws InterruptedException {semaphore.acquire();try {executor.execute(() -> {try {command.run();} finally {semaphore.release();}});} catch (RejectedExecutionException e) {semaphore.release();}}}
本文的例子可参考https://github.com/ddean2009/learn-java-concurrency/tree/master/rejectPolicy
更多精彩内容且看:
- 区块链从入门到放弃系列教程-涵盖密码学,超级账本,以太坊,Libra,比特币等持续更新
- Spring Boot 2.X系列教程:七天从无到有掌握Spring Boot-持续更新
- Spring 5.X系列教程:满足你对Spring5的一切想象-持续更新
- java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程
更多内容请访问 flydean的博客
java中有界队列的饱和策略(reject policy)相关推荐
- JAVA中阻塞队列的类别和区别(转载)
这篇文章将介绍什么是阻塞队列,以及Java中阻塞队列的4种处理方式,并介绍Java 7中提供的7种阻塞队列,最后分析阻塞队列的一种实现方式. 阻塞队列(BlockingQueue)是一个支持两个附加操 ...
- java数组实现队列_使用数组在Java中进行队列实现
java数组实现队列 什么是队列? (What is a Queue?) Queue is a special type of data structure, which is designed to ...
- Java实现自定义队列和树结构_实现二叉树的层序遍历,说说Java中的队列结构(实现一个Java的队列)...
几次面试都被问到二叉树的层序遍历,需要用到队列这个数据结构,我一直想使用一个队列来实现,但是java里没有一种好的队列的数据结构,我又一次面试用ArrayList去当队列用,但是被面试官说到,是不对的 ...
- 聊聊Java中的并发队列中 有界队列和无界队列的区别
转载自 https://blog.csdn.net/AJ1101/article/details/81711812 本文主要总体的说一说各种并发队列 首先来一张全体照 从有界无界上分 常见的有界 ...
- Java中阻塞队列类型介绍
Java中的几种阻塞队列 Java中的BlockingQueue接口是一个线程安全的存取队列,适用于生产者消费者的应用场景中,支持两个附加操作: 生产者线程会一直不断的往阻塞队列中放入数据,直到队列满 ...
- java 中 阻塞队列 非阻塞队列 和普通队列的区别
转载自 https://blog.csdn.net/u012881904/article/details/51491736 阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻 ...
- java中使用队列:java.util.Queue
在java5中新添加了java.util.Queue接口,用以支持队列的常见操作.该接口扩展了java.util.Collection接口. Queue使用时要尽量避免Collection的add() ...
- Java中的队列同步器AQS
一.AQS概念 1.队列同步器是用来构建锁或者其他同步组件的基础框架,使用一个int型变量代表同步状态,通过内置的队列来完成线程的排队工作. 2.下面是JDK8文档中对于AQS的部分介绍 public ...
- Java中关于队列与栈的区别
一:栈 ,先进后出,通常叫压栈,往箱子里面放衣服,最先进去,先进后出,后进先出LIFO.底层采用Vector import java.util.Stack;public class StackQue ...
最新文章
- 让用VS2012/VS2013编写的程序在XP中顺利运行
- golang 位操作
- 使命召唤手游迎来欧阳娜娜,这阵容够豪华,玩家期待吗?
- 让经纬度数据带矢量方向_惊艳!这样处理可得到细至可用于交通模型的路网数据...
- 计算机仿真在机械应用,浅谈计算机仿真在机械的应用.doc
- C语言char的大小写转换
- java实现单向循环链表_java实现的带头单向循环链表
- 博文视点大讲堂第30期——职场新人胜出的关键点
- 博客6:磁盘以及创建文件系统的相关知识点
- 开源项目工时系统_自研工时管理系统,究竟好不好? | AceTeamwork
- 如何看待浏览器越来越臃肿,手机浏览器现状堪忧
- Unity 实现批量Build打包
- 计算机显示找不到gpedit,Win7系统gpedit.msc找不到的解决方法
- 移动平均线rolling()与加权移动平均线ewm()
- 叶脊网络架构(Spine-Leaf)
- KylinV10上qt5.9开发应用打包步骤(四)--linuxdeployqt源码编译
- 局域网常用的几种网络拓扑结构及其特点。
- InterviewQuestion
- 【图像去噪】基于非局部均值(NLM)滤波图像去噪含Matlab源码
- postfix+dovecot+openldap+extmail+spamassassin+M...
热门文章
- 安卓和Linux动态库一样吗,在Linux环境下编译Android下的最新版ffmpeg+x264单个动态库(.so)...
- VC星号密码查看器源码
- RedrawWindow, UpdateWindow,InvalidateRect 用法
- C++ 面向对象(一)继承:继承、对象切割、菱形继承、虚继承、继承与组合
- Linux 基础I/O :文件描述符,重定向,文件系统,软链接和硬链接,动态库和静态库
- IntelliJ IDEA不好用?那是因为没掌握这些技巧
- 空降进阿里的 P10 都是什么人
- JAVA多线程之扩展ThreadPoolExecutor
- 顺序表、链表、双向循环链表
- 大话ion系列(三)