FutureTask

类的结构:
image.png
demo代码:
image.png
上述代码中通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

api:

  1. //取消任务的执行。参数指定是 否立即中断任务执行,或者等等任务结束
  2. boolean cancel (boolean mayInterruptIfRunning)
  3. //任务是否已经取消,任务正常完成前将其取消,则返回 true
  4. boolean isCancelled ()
  5. //任务是否已经完成。需要注意的是如果任务正常终止、异常或 取消,都将返回true
  6. boolean isDone ()
  7. //等待任务执行结 束,然后获得V类型的结果。InterruptedException 线程被中断异常,
  8. // ExecutionException任务执行异常,如果任务被取消,还会抛出 CancellationException
  9. V get () throws InterruptedException, ExecutionException
  10. //同上面的get功能一样,多了设置超时时间。 参数timeout指定超时时间,uint指定时间的单位
  11. //如果计算超时,将抛出TimeoutException
  12. V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException

备注:throws InterruptedException的方法一般都会堵塞

缺点:

并发执行多任务时:因为Future提供的get()方法是阻塞的。如果第一个任务执行时间很长,主线程就会堵塞在第一个任务上。在某些业务场景中,比如向不同电商平台询价,并保存价格,如果其中一个平台询价时间长,不希望去影响这个任务影响其他任务的执行,并且部分平台查询失败的情况也不影响业务运行
就有了CompletionService

CompletionService

CompletionService可以实现先执行完的任务先取结果,不再依赖任务顺序。
demo:

  1. //创建线程池
  2. ExecutorService executor=Executors.newFixedThreadPool(10);
  3. //创建CompletionService
  4. CompletionService<Integer> cs = new ExecutorCompletionService<>(executor);
  5. //异步向电商S1询价
  6. cs.submit(()‐>getPriceByS1());
  7. //异步向电商S2询价
  8. cs.submit(()‐>getPriceByS2());
  9. //异步向电商S3询价
  10. cs.submit(()‐>getPriceByS3());
  11. //将询价结果异步保存到数据库
  12. for (int i= 0; i< 3; i++) {
  13. Integer r = cs.take().get();
  14. executor.execute(()‐>save(r));
  15. }

实现原理

内部有一个先进先出的阻塞队列,用于保存已经执行完成的Future,通过调用它的 take方法或poll方法可以获取到一个已经执行完成的Future,进而通过调用Future接口实现类 的get方法获取最终的结果
所以当需要批量提交异步任务的时候优先考虑CompletionService

api:

image.png