一、 Callable,Future,FutureTask
Callable接口与Runnable接口类似,封装了一个异步运行的任务,但与run方法不同,它的call方法可以有一个返回值并且可以抛出异常。Callable接口是个参数化的类型 public interface Callable{ V call() throws Exception} ,类型参数就是返回值的类型。
Future接口用于表示异步计算的结果,并提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用get方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由cancel方法来执行。还提供了其他方法,以确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用Future但又不提供可用的结果,则可以声明Future>形式类型、并返回null作为底层任务的结果。下面是JDK给的例子:
interface ArchiveSearcher { String search(String target); }
class App {
ExecutorService executor = ...
ArchiveSearcher searcher = ...
void showSearch(final String target)throws InterruptedException {
Futurefuture = executor.submit(new Callable() {
public String call() {
return searcher.search(target);
}});
displayOtherThings(); // do other things while searching
try {
displayText(future.get()); // use future
} catch (ExecutionException ex) { cleanup(); return; }
}
}
FutureTask类代表可取消的异步计算,它采用包装器机制,可将Callable转换成Runnable和Future,它同时实现了这两个接口。下面是用法实例:
CallablemyCallable = new MyCallable();
FutureTask task = new FutureTask(myCallable);
new Thread(task).start();
...
T result = task.get();
二、执行器
1.Executor接口与ThreadPoolExecutor
Executor用于执行已提交的Runnable任务,它将任务的提交与每个任务如何运行的机制(包括线程使用的细节、调度等)分离开来。它仅提供了一个excecute方法。它有两个子接口:ExcecuteService和SheduledExecutorService
ExecutorService提供了相关方法以管理终止,以及相关方法以跟踪一个或多个异步任务执行状况。可以关闭ExecutorService,shutdown方法被调用后将等待已提交的任务运行结束才会关闭服务,而shutdownNow方法将阻止任务启动并尝试停止正在运行的任务。被关闭的ExecutorService没有等待启动的任务,没有正在运行的任务,也无法向其提交新的任务。应该关闭不再使用的ExecutorService以回收资源。
ThreadPoolExecutor线程池实现了ExecutorService接口。使用线程池可以避免频繁创建线程的开销,适合执行大量生命周期较短的任务。对于每个任务,如果线程池中有线程可用,则让它立即执行任务,否则创建一个新线程让其执行或者将其放入等待队列。
线程池的常见用法:
(1)调用Executors中的静态方法或者ThreadPoolExecutor构造方法创建线程池对象。
(2)调用submit提交Runnable或Callable对象,
(3)如果要取消一个任务,那就应该保存好返回的Future对象。
(4)当不再提交任何任务时,应该调用shutdown方法关闭线程池
2. 控制任务组
ExecutorService执行器提供了许多控制任务执行的方法。
shutdownNow方法可以取消所有正在执行的任务和未执行的任务。
invokeAny方法将所有所有任务对象作为一个集合提交到执行器中,并返回一个Future列表。当这些任务中的任一个执行完毕后返回结果,无法知道返回的究竟是哪个任务的结果。此方法适合于多种方式并行处理一个问题的场景,只要求尽快得到结果,具体哪种方法起作用不关心。
invokeAll与invokeAny不同,所有任务都会返回结果。但如果Future列表中第一个对应任务执行时间最长,则其他任务结果的获得不得不等待。可以使用ExecutorCompletionService来获取顺序返回的任务结果。
ExecutorCompletionService的用法:
ExecutorCompletionService service = newExecutorCompletionService(executor);
for(Callabletask : tasks)
service.submit(task);
for(int i=0;i
processFurther(service.take().get());