这里是 Java Concurrency in Practice 中的代码,展示了如何通过使用Semaphore
绑定任务注入速率来在工作队列已满时执行块。信号量等于池大小加上您想要允许的排队任务数。
public class BoundedExecutor {
private final Executor exec;
private final Semaphore semaphore;
public BoundedExecutor(Executor exec, int bound) {
this.exec = exec;
this.semaphore = new Semaphore(bound);
}
public void submitTask(final Runnable command)
throws InterruptedException {
semaphore.acquire();
try {
exec.execute(new Runnable() {
public void run() {
try {
command.run();
} finally {
semaphore.release();
}
}
});
} catch (RejectedExecutionException e) {
semaphore.release();
}
}
}
我的问题是关于
catch(RejectedExecutionException e){semaphore.release(); }
当我们上面有semaphore.acquire();
时,它是不必要的吗?
如果工作队列已满,那么' semaphore.acquire'应该是阻止,并且没有RejectedExecutionException
。
答案 0 :(得分:1)
文档说throws RejectedExecutionException if this task cannot be accepted for execution
。如果任何原因无法接受任务,您希望确定信号量已被释放。
答案 1 :(得分:1)
如果无法接受任务,执行者可以抛出RejectedExecutionException
。如果发生这种情况,则意味着已经获得了信号量,但执行者认为它无法接受任务。
此行为取决于执行程序的实现,因此它独立于成功调用acquire()
,如果确实发生,则必须释放信号量以指示新任务有空闲插槽。 / p>
理想情况下,该方法应返回true或false以指示是否发生了这种情况。
答案 2 :(得分:0)
即使您认为执行人永远不会拒绝您的请求(例如,因为您认为该约束低于遗嘱执行人的池大小+队列限制),但仍然不要依赖您假设。即使您的假设是错误的,上述代码也能正常运行,如果您的假设是正确的,则不会产生任何负面影响。
按照目前的情况,上面的代码不会在执行程序上设置任何边界,只会设置信号量上的绑定,所以当然可以选择比执行程序接受的更高的边界。
答案 3 :(得分:0)
我认为你将内部执行器(在构造函数中通过参数传递)与外部执行器(BoundedExecutor)混淆。即使BoundedExecutor类在名称中有执行程序单词,并且有一个提交任务的方法,它也没有实现Executor
接口。
它是一种装饰类。它的作用是提供普通Executor提供的功能,但限制了可以提交的任务数量。
您提到的异常由内部执行程序的execute
方法抛出。因为临界区可以抛出异常,所以需要在finally子句中释放锁。否则,如果提交失败,您将错误地计算一个。