文章目录

  • 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)相关推荐

  1. JAVA中阻塞队列的类别和区别(转载)

    这篇文章将介绍什么是阻塞队列,以及Java中阻塞队列的4种处理方式,并介绍Java 7中提供的7种阻塞队列,最后分析阻塞队列的一种实现方式. 阻塞队列(BlockingQueue)是一个支持两个附加操 ...

  2. java数组实现队列_使用数组在Java中进行队列实现

    java数组实现队列 什么是队列? (What is a Queue?) Queue is a special type of data structure, which is designed to ...

  3. Java实现自定义队列和树结构_实现二叉树的层序遍历,说说Java中的队列结构(实现一个Java的队列)...

    几次面试都被问到二叉树的层序遍历,需要用到队列这个数据结构,我一直想使用一个队列来实现,但是java里没有一种好的队列的数据结构,我又一次面试用ArrayList去当队列用,但是被面试官说到,是不对的 ...

  4. 聊聊Java中的并发队列中 有界队列和无界队列的区别

    转载自 https://blog.csdn.net/AJ1101/article/details/81711812 本文主要总体的说一说各种并发队列  首先来一张全体照  从有界无界上分  常见的有界 ...

  5. Java中阻塞队列类型介绍

    Java中的几种阻塞队列 Java中的BlockingQueue接口是一个线程安全的存取队列,适用于生产者消费者的应用场景中,支持两个附加操作: 生产者线程会一直不断的往阻塞队列中放入数据,直到队列满 ...

  6. java 中 阻塞队列 非阻塞队列 和普通队列的区别

    转载自 https://blog.csdn.net/u012881904/article/details/51491736 阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻 ...

  7. java中使用队列:java.util.Queue

    在java5中新添加了java.util.Queue接口,用以支持队列的常见操作.该接口扩展了java.util.Collection接口. Queue使用时要尽量避免Collection的add() ...

  8. Java中的队列同步器AQS

    一.AQS概念 1.队列同步器是用来构建锁或者其他同步组件的基础框架,使用一个int型变量代表同步状态,通过内置的队列来完成线程的排队工作. 2.下面是JDK8文档中对于AQS的部分介绍 public ...

  9. Java中关于队列与栈的区别

    一:栈  ,先进后出,通常叫压栈,往箱子里面放衣服,最先进去,先进后出,后进先出LIFO.底层采用Vector import java.util.Stack;public class StackQue ...

最新文章

  1. 让用VS2012/VS2013编写的程序在XP中顺利运行
  2. golang 位操作
  3. 使命召唤手游迎来欧阳娜娜,这阵容够豪华,玩家期待吗?
  4. 让经纬度数据带矢量方向_惊艳!这样处理可得到细至可用于交通模型的路网数据...
  5. 计算机仿真在机械应用,浅谈计算机仿真在机械的应用.doc
  6. C语言char的大小写转换
  7. java实现单向循环链表_java实现的带头单向循环链表
  8. 博文视点大讲堂第30期——职场新人胜出的关键点
  9. 博客6:磁盘以及创建文件系统的相关知识点
  10. 开源项目工时系统_自研工时管理系统,究竟好不好? | AceTeamwork
  11. 如何看待浏览器越来越臃肿,手机浏览器现状堪忧
  12. Unity 实现批量Build打包
  13. 计算机显示找不到gpedit,Win7系统gpedit.msc找不到的解决方法
  14. 移动平均线rolling()与加权移动平均线ewm()
  15. 叶脊网络架构(Spine-Leaf)
  16. KylinV10上qt5.9开发应用打包步骤(四)--linuxdeployqt源码编译
  17. 局域网常用的几种网络拓扑结构及其特点。
  18. InterviewQuestion
  19. 【图像去噪】基于非局部均值(NLM)滤波图像去噪含Matlab源码
  20. postfix+dovecot+openldap+extmail+spamassassin+M...

热门文章

  1. 安卓和Linux动态库一样吗,在Linux环境下编译Android下的最新版ffmpeg+x264单个动态库(.so)...
  2. VC星号密码查看器源码
  3. RedrawWindow, UpdateWindow,InvalidateRect 用法
  4. C++ 面向对象(一)继承:继承、对象切割、菱形继承、虚继承、继承与组合
  5. Linux 基础I/O :文件描述符,重定向,文件系统,软链接和硬链接,动态库和静态库
  6. IntelliJ IDEA不好用?那是因为没掌握这些技巧
  7. 空降进阿里的 P10 都是什么人
  8. JAVA多线程之扩展ThreadPoolExecutor
  9. 顺序表、链表、双向循环链表
  10. 大话ion系列(三)