package edu.washington.escience.myria.util.concurrent;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.google.common.base.Preconditions;
/**
* Simply wrap a 1-size {@link ThreadPoolExecutor}.
* */
class DefaultThreadAffinityExecutor implements ThreadAffinityExecutor {
/**
* The thread to run the jobs.
* */
private volatile ThreadPoolExecutor backendThread;
/**
* @param threadFactory thread factory for creating threads in the executor.
* */
DefaultThreadAffinityExecutor(final ThreadFactory threadFactory) {
backendThread =
new ThreadPoolExecutor(
1, 1, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory);
}
@Override
public void execute(final Runnable command) {
Preconditions.checkNotNull(command);
this.submit(Executors.callable(command));
}
@Override
public <T> ExecutionFuture<T> submit(final Callable<T> task) {
Preconditions.checkNotNull(task);
ExecutableExecutionFuture<T> r = new ExecutableExecutionFuture<T>(task, true);
backendThread.submit((Callable<T>) r);
return r;
}
/**
* Normal shutdown, wait until the current running task finishes.
* */
void shutdown() {
backendThread.shutdown();
backendThread = null;
}
/**
* Abrupt shutdown, interrupt the execution thread.
*
* @return list of {@link Runnable}s that never commenced execution.
* */
List<Runnable> shutdownNow() {
try {
return backendThread.shutdownNow();
} finally {
backendThread = null;
}
}
/**
* Returns <tt>true</tt> if all tasks have completed following shut down. Note that <tt>isTerminated</tt> is never
* <tt>true</tt> unless either <tt>shutdown</tt> or <tt>shutdownNow</tt> was called first.
*
* @return <tt>true</tt> if all tasks have completed following shut down
*/
boolean isTerminated() {
return backendThread.isTerminated();
}
/**
* Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current
* thread is interrupted, whichever happens first.
*
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return <tt>true</tt> if this executor terminated and <tt>false</tt> if the timeout elapsed before termination
* @throws InterruptedException if interrupted while waiting
*/
boolean awaitTermination(final long timeout, final TimeUnit unit) throws InterruptedException {
return backendThread.awaitTermination(timeout, unit);
}
}