package org.jbehave.eclipse.util;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A monitored executor is an {@link Executor} that keeps track of all issued
* tasks and allows a thread to wait for their completion.
*
* There is no check that would prevent calling awaitCompletion() from within a
* scheduled task, which will lead to a dead-lock.
*/
public class MonitoredExecutor implements Executor {
/** Counter for active tasks */
private final AtomicInteger activeCount = new AtomicInteger(0);
/** signal object for all tasks finished */
private final Object finishedSignal = new Object();
/** The actual executor for the tasks */
private final Executor executor;
/**
* Constructor
*
* @param executor
* the executor to use in the background
*/
public MonitoredExecutor(Executor executor) {
this.executor = executor;
}
/**
* Waits for all scheduled tasks to complete. Must not be called from within
* a scheduled task.
*
* @throws InterruptedException
* when the waiting thread is interrupted
*/
public void awaitCompletion() throws InterruptedException {
synchronized (finishedSignal) {
if (activeCount.get() > 0) {
finishedSignal.wait();
}
}
}
/** {@inheritDoc} */
public void execute(final Runnable runnable) {
activeCount.incrementAndGet();
executor.execute(new Runnable() {
public void run() {
try {
runnable.run();
} finally {
onRunnableReturned();
}
}
});
}
private void onRunnableReturned() {
synchronized (finishedSignal) {
if (activeCount.decrementAndGet() == 0) {
finishedSignal.notifyAll();
}
}
}
}