1

这是 Java Concurrency in Practice 一书中 BoundedExecutor 类的实现:

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();
        }
    }
}

是否有原因导致 RejectedExecutionException 被捕获而不是让它进一步传播?在这种情况下,如果任务被拒绝,那么提交任务的人就不会更聪明了。

用 finally 块替换 catch 块不是更好吗?

这是我接受 Callable 而不是 Runnable 的 BoundedExecutor 的实现:

public class BoundedExecutor {
    private final ExecutorService exec; 
    private final Semaphore semaphore; 

    public BoundedExecutor(ExecutorService exec, int bound) { 
        this.exec = exec; 
        this.semaphore = new Semaphore(bound); 
    } 

    public <V> Future<V> submitTask(final Callable<V> command) throws InterruptedException { 
        semaphore.acquire(); 

        try { 
            return exec.submit(new Callable<V>() {
                @Override public V call() throws Exception { 
                    try { 
                        return command.call();
                    } finally { 
                        semaphore.release(); 
                    } 
                } 
            });
        } catch (RejectedExecutionException e) { 
            semaphore.release();
            throw e;
        }
    }
}

这是一个正确的实现吗?

谢谢!

4

2 回答 2

0

我猜你的解决方案是不正确的。该调用exec.submit(Callable task)为客户端提供了对 Future 的引用,在此 Future 上调用 get() 为用户提供了所需的结果或异常(CancellationException、ExecutionException 等)。

因此将 exec.submit 包装在 try catch 块中将无济于事,并且将 execute 调用包装在 try catch 块中的原始实现是正确的。

或者,您可以将用户的命令包装在将来的任务中,而不是可调用的,并在您的 FutureTask 中覆盖 done 方法以调用 semaphore.release()。

于 2012-02-21T09:10:15.953 回答
0

我看到将 catch 更改为 finally 的一个问题是,如果确实提交了任务并且没有抛出 RejectedExecutionException,您最终将释放信号量两次而不是一次。如果要在 catch 块版本中传播异常,只需throw e;在释放信号量后添加即可。

于 2012-02-21T09:12:26.427 回答