Future 的用法

多线程场景时,一般是实现 runnable 接口,覆写 run 方法,返回值是 void 类型,因此这种情况下不需要线程的返回结果。
如果需要线程的返回结果,就需要用 callable 接口来代替了。
callable 用法和 runnable 一样,只不过覆写的是 call 方法,该方法有一个泛型返回值类型,可以根据需要指定。
那么何时到 Future 呢?当你启动 callable 线程时,就可以声明一个 Future 对象,用于接收返回结果。
Futrue 可以监视目标线程调用 call 的情况,当你调用 Future 的 get () 方法以获得结果时,调用方的线程就被阻塞,直到目标线程的 call 方法结束并返回结果。
Future 接口,一般都是取回 Callable 执行的状态用的。其中的主要方法:

cancel,取消 Callable 的执行,当 Callable 还没有完成时
get,获得 Callable 的返回值
isCanceled,判断是否取消了
isDone,判断是否完成
举个栗子。
四个刚需(线程)去买房摇号,future 获取摇号结果。摇号结果未出,就一直阻塞。

  1. public class FutureTest {
  2. /**
  3. * 买房摇号
  4. */
  5. public static class Yaohao implements Callable<Integer> {
  6. /**
  7. * 返回摇号结果
  8. * @return 0:中签 1:没中
  9. * @throws Exception
  10. */
  11. @Override
  12. public Integer call() throws Exception {
  13. Random random = new Random();
  14. //模拟摇号,10天内出结果
  15. TimeUnit.SECONDS.sleep(random.nextInt(10));
  16. int result = random.nextInt(2);
  17. System.out.println(" "+Thread.currentThread().getName()+" is done!");
  18. return result;
  19. }
  20. }
  21. public static void main(String[] args) throws InterruptedException, ExecutionException {
  22. Yaohao gangxu1 = new Yaohao();
  23. Yaohao gangxu2 = new Yaohao();
  24. Yaohao gangxu3 = new Yaohao();
  25. Yaohao gangxu4 = new Yaohao();
  26. ExecutorService es = Executors.newCachedThreadPool();
  27. Future<Integer> result1 = es.submit(gangxu1);
  28. Future<Integer> result2 = es.submit(gangxu2);
  29. Future<Integer> result3 = es.submit(gangxu3);
  30. Future<Integer> result4 = es.submit(gangxu4);
  31. es.shutdown();
  32. System.out.println("刚需1,摇号结果:"+(result1.get()==1?"中签":"没中"));
  33. System.out.println("刚需2,摇号结果:"+(result2.get()==1?"中签":"没中"));
  34. System.out.println("刚需3,摇号结果:"+(result3.get()==1?"中签":"没中"));
  35. System.out.println("刚需4,摇号结果:"+(result4.get()==1?"中签":"没中"));
  36. }
  37. }

CompletableFuture 的用法


创建异步操作,runAsync(不支持返回值) 和 supplyAsync 方法(支持返回值)
计算结果完成时的回调方法
whenComplete:执行完当前任务的线程,继续执行 whenComplete 的任务。
whenCompleteAsync: 执行完当前任务的线程,把 whenCompleteAsync 的任务继续提交给线程池来执行。
exceptionally:当前任务出现异常时,执行 exceptionally 中的回调方法。
thenApply 方法,当一个线程依赖另一个线程时,可以使用 thenApply 方法来把这两个线程串行化。
handle 方法
handle 是执行任务完成时对结果的处理。
handle 方法和 thenApply 方法处理方式基本一样。不同的是 handle 是在任务完成后再执行,还可以处理异常的任务。thenApply 只可以执行正常的任务,任务出现异常则不执行 thenApply 方法。
thenAccept 消费处理结果,接收任务的处理结果,并消费处理,无返回结果。
thenRun 方法,跟 thenAccept 方法不一样的是,不关心任务的处理结果。只要上面的任务执行完成,就开始执行 thenAccept 。
thenCombine 合并任务,thenCombine 会把 两个 CompletionStage 的任务都执行完成后,把两个任务的结果一块交给 thenCombine 来处理。
thenCompose 方法,thenCompose 方法允许你对两个 CompletionStage 进行流水线操作,第一个操作完成时,将其结果作为参数传递给第二个操作。

实际的例子可以参考下面这篇文章,写得很简单明了。
https://www.jianshu.com/p/6bac52527ca4

Future 和 CompletableFuture 的区别

Future 在 Java5 就引入了。

优点:一定程度上让一个线程池内的任务异步执行了
缺点:传统回调最大的问题就是不能将控制流分离到不同的事件处理器中。例如主线程等待各个异步执行的线程返回的结果来做下一步操作,则必须阻塞在 future.get () 的地方等待结果返回。这时候又变成同步了。

CompletableFuture 在 Java8 引入。

实现了 Future 和 CompletionStage 接口,保留了 Future 的优点,并且弥补了其不足。即异步的任务完成后,需要用其结果继续操作时,无需等待。可以直接通过 thenAccept、thenApply、thenCompose 等方式将前面异步处理的结果交给另外一个异步事件处理线程来处理。
可见,这种方式才是我们需要的异步处理。一个控制流的多个异步事件处理能无缝的连接在一起。
————————————————
版权声明:本文为CSDN博主「编程南山下」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_28908085/article/details/108267347