携带结果的任务Callable与Future
Callable
类似于 Runnable 接口,但它可以返回任何对象并能够抛出异常。
Future
Java Callable 任务返回 java.util.concurrent.Future 对象。使用 Java Future 对象,我们可以找出 Callable 任务的状态并获得返回的对象。它提供了 get() 方法,可以等待 Callable 完成然后返回结果。 Java Future 提供了 cancel() 方法来取消关联的 Callable 任务。有一个重载版本的 get() 方法,我们可以在其中指定等待结果的时间,这有助于避免当前线程长时间阻塞。有 isDone() 和 isCancelled() 方法可以找出关联的 Callable 任务的当前状态。
Future 规范中隐含的是任务生命周期只能向前移动,不能向后移动。
将 Runnable 或 Callable 提交给 Executor 构成了从提交线程到执行任务的线程的安全发布。类似地,为 Future 设置结果值构成了从计算它的线程到通过 get 检索结果的任何线程的的安全发布。
CompletionService
一种将新异步任务的生成与已完成任务结果的使用分离开来的服务。生产者提交任务执行。消费者接受已完成的任务并按照他们完成的顺序处理他们的结果。
CompletionService 结合了 Executor 和 BlockingQueue 的功能。
假设我们要向线程池提交一批任务,并获取任务结果。一般的方式是提交任务后,从线程池得到一批 Future 对象集合,然后依次调用其 get() 方法。
这里有个问题:因为我们会要按固定的顺序来遍历 Future 元素,而 get() 方法又是阻塞的,因此如果某个 Future 对象执行时间太长,会使得我们的遍历过程阻塞在该元素上,无法及时从后面早已完成的 Future 当中取得结果。
有了 CompletionService,你不需要再持有 Future 集合。如果要得到最早的执行结果,只需要像下面这样:
String result = completionService.take().get();
这个 take() 方法返回的是最早完成的任务的结果,这个就解决了一个任务被另一个任务阻塞的问题。
为任务设置时间限制
Future.get 的定时版本支持此要求:它会在结果准备好后立即返回,但如果结果在超时期限内未准备好,则抛出 TimeoutException。