public class SynchronousExecutor implements ExecutorService {
@Override
public void execute(Runnable command) {
throw new UnsupportedOperationException();
}
@Override
public void shutdown() {
throw new UnsupportedOperationException();
}
@Override
public List<Runnable> shutdownNow() {
throw new UnsupportedOperationException();
}
@Override
public boolean isShutdown() {
throw new UnsupportedOperationException();
}
@Override
public boolean isTerminated() {
throw new UnsupportedOperationException();
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
throw new UnsupportedOperationException();
}
@Override
public <T> Future<T> submit(Callable<T> task) {
T t = null;
Throwable exception = null;
try {
t = task.call();
} catch (Throwable e) {
exception = e;
}
return new SynchronousFuture<T>(t, exception);
}
@Override
public <T> Future<T> submit(Runnable task, T result) {
throw new UnsupportedOperationException();
}
@Override
public Future<?> submit(Runnable task) {
throw new UnsupportedOperationException();
}
@Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
throw new UnsupportedOperationException();
}
@Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException {
throw new UnsupportedOperationException();
}
@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
// TODO Auto-generated method stub
throw new UnsupportedOperationException();
}
@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException,
ExecutionException, TimeoutException {
throw new UnsupportedOperationException();
}
}
This implements ExecutorService but I've changed the behavior of submit, by executing the Callable, synchronously. The submit method returns a SynchronousFuture, which contains the return value of the Callable, or a Throwable if the call failed. I return my SynchronousExecutor in getDefaultExecutorService, however In situations where I want asynchronous execution, I override this method and return a standard ExecutorService.
protected ExecutorService getDefaultExecutorService() {
return new SynchronousExecutor();
}
The SynchronousExecutor is entirely stateless so we really could return the same instance every time instead of creating new objects. SynchronousFuture is pretty basic; many of the Future methods do not apply for synchronous execution, so I indicate that by throwing UnsupportedOperationException.
public class SynchronousFuture<t> implements Future<t> {
private T t;
private Throwable e;
public SynchronousFuture(T t, Throwable e) {
this.t = t;
this.e = e;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
throw new UnsupportedOperationException();
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return true;
}
@Override
public T get() throws InterruptedException, ExecutionException {
if (e != null) {
throw new ExecutionException(e);
}
return t;
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
throw new UnsupportedOperationException();
}
}
Now we can submit Callables, just as you would to a typical ExecutorService, but it is executed synchronously. The call to the get method of SynchronousFuture never blocks since it's already complete.
No comments:
Post a Comment