这个关于信号量的代码片段是否必要?

时间:2015-10-22 13:02:12

标签: java concurrency semaphore

这里是 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

4 个答案:

答案 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子句中释放锁。否则,如果提交失败,您将错误地计算一个。