|
|
< Day Day Up > |
|
10.2 ExecutorsJava's implementation of thread pools is based on an executor. An executor is a generic concept modelled by this interface: package java.util.concurrent;
public interface Executor {
public void execute(Runnable task);
}Executors are a useful design pattern for multithreaded programs because they allow you to model your program as a series of tasks. You don't need to worry about the thread details associated with the task: you simply create the task and pass it to the execute() method of an appropriate executor. J2SE 5.0 comes with two kinds of executors. It comes with a thread pool executor, which we'll show next. It also provides a task scheduling executor, which we examine in Chapter 11. Both of these executors are defined by this interface: package java.util.concurrent;
public interface ExecutorService extends Executor {
void shutdown( );
List shutdownNow( );
boolean isShutdown( );
boolean isTerminated( );
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
<T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks)
throws InterruptedException;
<T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
<T> T invokeAny(Collection<Callable<T>> tasks)
throws InterruptedException, ExecutionException;
<T> T invokeAny(Collection<Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}This interface provides a means for you to manage the executor and its tasks. The shutdown() method gracefully terminates the executor: any tasks that have already been sent to the executor are allowed to run, but no new tasks are accepted. When all tasks are completed, the executor stops its thread(s). The shutdownNow() method attempts to stop execution sooner: all tasks that have not yet started are not run and are instead returned in a list. Still, existing tasks continue to run: they are interrupted, but it's up to the runnable object to check its interrupt status and exit when convenient. So there's a period of time between calling the shutdown() or shutdownNow() method and when tasks executing in the executor service are all complete. When all tasks are complete (including any waiting tasks), the executor service enters a terminated state. You can check to see if the executor service is in the terminated state by calling the isTerminated() method (or you can wait for it to finish the pending tasks by calling the awaitTerminated() method). An executor service also allows you to handle many tasks in ways that the simple Executor interface does not accommodate. Tasks can be sent to an executor service via a submit() method, which returns a Future object that can be used to track the progress of the task. The invokeAll( ) methods execute all the tasks in the given collection. The invokeAny() methods execute the tasks in the given collection, but when one task has completed, the remaining tasks are subject to cancellation. We'll discuss Future objects and cancellation later in this chapter. |
|
|
< Day Day Up > |
|