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

更多内容请访问 flydean的博客

java中有界队列的饱和策略(reject policy)的更多相关文章

  1. Java 中的队列 Queue

    一.队列的定义 我们都知道队列(Queue)是一种先进先出(FIFO)的数据结构,Java中定义了java.util.Queue接口用来表示队列.Java中的Queue与List.Set属于同一个级别 ...

  2. java中使用队列:java.util.Queue (转)

    Queue接口与List.Set同一级别,都是继承了Collection接口.LinkedList实现了Queue接 口.Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类 ...

  3. Java中的队列都有哪些,有什么区别?

    Queue: 基本上,一个队列就是一个先入先出(FIFO)的数据结构 Queue接口与List.Set同一级别,都是继承了Collection接口.LinkedList实现了Deque接 口. 1.未 ...

  4. java中线程队列BlockingQueue的用法

    在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利.本文 ...

  5. Java中阻塞队列的使用

    http://blog.csdn.net/qq_35101189/article/details/56008342 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如 ...

  6. java中的队列

    转载自:http://blog.csdn.net/guijava/article/details/3784658 在java5中新增加了java.util.Queue接口,用以支持队列的常见操作.Qu ...

  7. Java中的队列Queue,优先级队列PriorityQueue

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

  8. Java中的队列:java.util.Queue接口

    队列是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作. Queue接口与List.Set同一级别,都是继承了Collection接口.Linked ...

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

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

随机推荐

  1. Python常用模块之configparser

    ConfigParser简介 ConfigParser 是用来读取配置文件的包.配置文件的格式如下:中括号“[ ]”内包含的为section.section 下面为类似于key-value 的配置内容 ...

  2. SWUST OJ 1012哈希表(链地址法处理冲突)

    哈希表(链地址法处理冲突) 1000(ms) 10000(kb) 2676 / 6911 采用除留余数法(H(key)=key %n)建立长度为n的哈希表,处理冲突用链地址法.建立链表的时候采用尾插法 ...

  3. 跑马灯效果、jquery封装、$.fn和$.extend方法使用

    代码 index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...

  4. PTA | 1009说反话(20分)

    给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出. 输入格式: 测试输入包含一个测试用例,在一行内给出总长度不超过80的字符串.字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有 ...

  5. 深入理解== 和 equals 的本质区别

    简介 初学者常常被"= =“和‘equals ’所折磨,为什么,因为他们的大概意思相同,都是比较两个对象是否相等,而又不搞不清他们的具体比较两个对象相等的原理是什么,所以经常搞混淆,接下来我 ...

  6. 【java设计模式】(7)---策略模式(案例解析)

    策略模式 一.概念 1.理解策略模式 策略模式是一种行为型模式,它将对象和行为分开,将行为定义为 一个行为接口 和 具体行为的实现.策略模式最大的特点是行为的变化,行为之间可以相互替换. 每个if判断 ...

  7. python 判断一个字符串是否是小数

    """练习判断一个小数1.判断是否合法2.合法需要有一个小数点3.小数点左边必须是个整数,右边必须是个正整数 """ def xiaoshu ...

  8. 域控安全-EventID 4662&Powershell将Schema下Objects的schemaIDGUID属性离线保存

    首先看一下EventID 4662的样子 0x01 什么情况下会产生该日志呢? 该日志出现在对Active Directory Object设置SACL时会出现 0x02 为什么要监控该日志呢? 1. ...

  9. 第十节:xml、re、logging模块

    XML模块:(用到的时候再看)tree=xml.parse('xmltest.xml')root= tree.getroot()print(root.tag) 打印对象的标签root.attrib 获 ...

  10. Linux/UNIX 下 “command not found” 原因分析及解决

    在使用 Linux/UNIX 时,会经常遇到 "command not found" 的错误,就如提示的信息,Linux /UNIX 没有找到该命令.原因无外乎你命令拼写错误或 L ...