Search code examples
javaexceptionconcurrencyexecutor

Java Concurrency in Practice: BoundedExecutor implementation


This is the implementation of the BoundedExecutor class in the Java Concurrency in Practice book:

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

Is there a reason why the RejectedExecutionException is being caught instead of letting it propagate further? In this case, if the task is rejected, whoever submits the task will be none the wiser.

Isn't is better to just replace the catch-block with a finally-block?

This is my implementation of a BoundedExecutor that accepts a Callable instead of a Runnable:

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

Is it a correct implementation?

Thanks!


Solution

  • One problem I see with changing the catch to a finally is that, in the event that the task does get submitted and a RejectedExecutionException is not thrown, you will end up releasing the semaphore twice instead of just once. If you want to propagate the exception in the catch block version, you can simply add throw e; after releasing the semaphore.