My question is strongly related to this one here.
As was posted there, I would like the main thread to wait until the work queue is empty and all tasks have finished. The pr
This one was actually rather interesting problem to solve. I must warn that I have not tested the code fully.
The idea is to simply track the task execution:
if task is successfully queued, counter is incremented by one
if task is cancelled and it has not been executed, counter is decremented by one
if task has been executed, counter is decremented by one
When shutdown is called and there are pending tasks, delegate will not call shutdown on the actual ExecutorService. It will allow queuing new tasks until pending task count reaches zero and shutdown is called on actual ExecutorService.
public class ResilientExecutorServiceDelegate implements ExecutorService {
private final ExecutorService executorService;
private final AtomicInteger pendingTasks;
private final Lock readLock;
private final Lock writeLock;
private boolean isShutdown;
public ResilientExecutorServiceDelegate(ExecutorService executorService) {
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
this.pendingTasks = new AtomicInteger();
this.readLock = readWriteLock.readLock();
this.writeLock = readWriteLock.writeLock();
this.executorService = executorService;
this.isShutdown = false;
}
private T addTask(Callable task) {
T result;
boolean success = false;
// Increment pending tasks counter
incrementPendingTaskCount();
try {
// Call service
result = task.call();
success = true;
} catch (RuntimeException exception) {
throw exception;
} catch (Exception exception) {
throw new RejectedExecutionException(exception);
} finally {
if (!success) {
// Decrement pending tasks counter
decrementPendingTaskCount();
}
}
return result;
}
private void incrementPendingTaskCount() {
pendingTasks.incrementAndGet();
}
private void decrementPendingTaskCount() {
readLock.lock();
if (pendingTasks.decrementAndGet() == 0 && isShutdown) {
try {
// Shutdown
executorService.shutdown();
} catch (Throwable throwable) {
}
}
readLock.unlock();
}
@Override
public void execute(final Runnable task) {
// Add task
addTask(new Callable