对于Java Concurrency in Practice一书中的BoundedExecutor,任务提交已被信号量限制。底层执行程序何时抛出RejectedExecutionException?也许当操作系统用完线程时?
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, RejectedExecutionException
{
semaphore.acquire();
try {
exec.execute(new Runnable() {
@Override public void run() {
try {
command.run();
} finally {
semaphore.release();
}
}
});
} catch (RejectedExecutionException e) {
semaphore.release();
throw e;
}
}
}
答案 0 :(得分:0)
Executor.execute()
的合同的一部分是它可以抛出RejectedExecutionException
:
如果无法接受执行此任务
这对于任何给定的Executor
实施意味着什么取决于该实施的自由裁量权。我可以创建一个拒绝任务的OnlyOnSundaysExecutor
,除非当周的当天是星期天。您必须查看各种Executor
实现的文档,以了解它们会在什么情况下抛出RejectedExecutionException
异常。
答案 1 :(得分:0)
无论出现异常的情况如何,即使发生异常,保持应用程序处于一致状态也很重要。
这里,已经获得的信号量应该总是被释放。对于应该在所有情况下都要发布的大多数资源,即使在特殊情况下,也可以使用try {} finally { /* release action */ }
构造来确保发布,但是在这里,我们有一个特殊情况,即应该只执行发布操作 在特殊情况下,与成功案例一样,提交的Runnable
将执行发布操作(请注意,在Runnable
内,确实正在使用finally
。)< / p>
因此代码应该在抛出RejectedExecutionException
时处理。我们可能希望为每个RuntimeException
或Error
执行此操作,但问题是,RejectedExecutionException
是唯一的异常类型,我们确信runnable永远不会被执行。对于所有其他类型的例外,它可能仍会运行。
为了使清理安全,您需要另一个原子切换:
public void submitTask(final Runnable command) throws InterruptedException {
AtomicBoolean proceed = new AtomicBoolean(true);
semaphore.acquire();
try {
exec.execute(new Runnable() {
@Override public void run() {
if(proceed.compareAndSet(true, false)) try {
command.run();
} finally {
semaphore.release();
}
}
});
} catch(Throwable e) {
if(proceed.compareAndSet(true, false)) semaphore.release();
throw e;
}
}
现在,在每种特殊情况下,都会尝试释放信号量,除非Runnable
标记它已经在运行。或者如果Runnable
检测到由于提交代码中的异常而释放了信号量,则try
将不会继续。
这当然比书中的例子更复杂,并且可能分散了示例的原始意图。此外,它使用Java 7功能,能够轻松捕获并重新抛出.mask
块的所有可能异常。这本书写完后就没用了。