FutureTask
类的结构:
demo代码:
上述代码中通过get方法获取执行结果,该方法会阻塞直到任务返回结果。
api:
//取消任务的执行。参数指定是 否立即中断任务执行,或者等等任务结束
boolean cancel (boolean mayInterruptIfRunning)
//任务是否已经取消,任务正常完成前将其取消,则返回 true
boolean isCancelled ()
//任务是否已经完成。需要注意的是如果任务正常终止、异常或 取消,都将返回true
boolean isDone ()
//等待任务执行结 束,然后获得V类型的结果。InterruptedException 线程被中断异常,
// ExecutionException任务执行异常,如果任务被取消,还会抛出 CancellationException
V get () throws InterruptedException, ExecutionException
//同上面的get功能一样,多了设置超时时间。 参数timeout指定超时时间,uint指定时间的单位
//如果计算超时,将抛出TimeoutException
V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
备注:throws InterruptedException的方法一般都会堵塞
缺点:
并发执行多任务时:因为Future提供的get()方法是阻塞的。如果第一个任务执行时间很长,主线程就会堵塞在第一个任务上。在某些业务场景中,比如向不同电商平台询价,并保存价格,如果其中一个平台询价时间长,不希望去影响这个任务影响其他任务的执行,并且部分平台查询失败的情况也不影响业务运行
就有了CompletionService
CompletionService
CompletionService可以实现先执行完的任务先取结果,不再依赖任务顺序。
demo:
//创建线程池
ExecutorService executor=Executors.newFixedThreadPool(10);
//创建CompletionService
CompletionService<Integer> cs = new ExecutorCompletionService<>(executor);
//异步向电商S1询价
cs.submit(()‐>getPriceByS1());
//异步向电商S2询价
cs.submit(()‐>getPriceByS2());
//异步向电商S3询价
cs.submit(()‐>getPriceByS3());
//将询价结果异步保存到数据库
for (int i= 0; i< 3; i++) {
Integer r = cs.take().get();
executor.execute(()‐>save(r));
}
实现原理
内部有一个先进先出的阻塞队列,用于保存已经执行完成的Future,通过调用它的 take方法或poll方法可以获取到一个已经执行完成的Future,进而通过调用Future接口实现类 的get方法获取最终的结果
所以当需要批量提交异步任务的时候优先考虑CompletionService
api: