Future 还是一 Java 1.5 带进来的产物,但过去那么多年实际代码中却很少有直接接触, 大约它多是隐匿在各种现成框架中默默的为我们服务。Future 本身不代表着多线程,而是代表着需异步计算的结果, 将来的一个期待,至于后来真正的结果不可知。在此之前想要获得一个 Runnable 在其他线程中的计算结果颇费波折,有了 Future 加之它身后的 Callable 一切就变得简单了。
对比一下 Java 1.5 前后的下面几个概念
- Callable 相当于之前的 Runnable, 只是 Callable 是有返回值的
- ExecuteService.submit(callable): Future 就类似于之前的 Thread(runnable)
 只是前者 submit 后立即执行,通过 get() 获得结果,后者用 start() 方法启动,runnable 是没有结果的。如果你也不想关心 Future 的结果也能 ExecuteService.submit(runnable)
只有 callable 被提交(到线程池) 后返回的 Future 才可能会有结果, 所以下面的代码永远等不到结果
Future<String> future = new FutureTask<>(() -> "Never");
String result = future.get();
最容易理解的 Future 基本使用代码如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |  ExecutorService executor = Executors.newCachedThreadPool(); //这是众多线程池类型的一种  Future<String> future = executor.submit(() -> { //Lambda 是一个 callable, 提交后便立即执行,这里返回的是 FutureTask 实例    System.out.println("Running task...");    Thread.sleep(5000);    return "Task return";  });  try {    Thread.sleep(1000);  } catch (InterruptedException e) {  }  System.out.println("Do something else");  //前面的的 Callable 在其他线程中运行着,现在想做别的事情都不影响  try {    System.out.println(future.get());  //等待 future 的执行结果  } catch (InterruptedException | ExecutionException e) {  }  executor.shutdown();  //不关闭的话程序都不会退出 | 
上面代码的执行结果如下
Running task...
Do something else
Task return
可以看出任务 submit() 之后立即执行,相当于 new Thread(...).start(). 注意 future.get() 需强制捕获的异常,它还有一个重载方法 future.get(long timeout, TimeUnit unit), 指定等待多长时间,超时报 TimeoutException. 无参的 get() 永远的等待。
Future 的其他几个方法如下:
boolean cancel(boolean mayInterruptIfRunning): 可以取消一个任务,调用能否成功因情况而定
boolean isCancelled()
boolean isDone()
我们也可以通过查询 isDone() 看任务是否执行完成,比如
| 1 2 3 4 5 | while(!future.isDone()) {   Thread.sleep(1000);   System.out.println("Waiting....") } future.get();    //到这时 future 已经执行完 | 
Future 解决了线程返回值的问题,但到了 Java 8 还不够,我们还需要处理多个 Future 之间的依赖,竞争关系,因此又带来了更强悍的 Future 的新实现 CompletableFuture。
进一步学习当中......
补充一下,在 Java 1.5 之前想要获得线程的执行结果可以参考如下代码
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // AtomicReference<String> reference = new AtomicReference<>();  StringBuffer sb = new StringBuffer();  new Thread(() -> {    try {      Thread.sleep(5000);    } catch (InterruptedException e) {      e.printStackTrace();    }     // reference.set("I'm done");      sb.append("I'm done");  }).start(); // while(reference.get() == null) { // } // System.out.println(reference.get());  while(sb.length() == 0) {  }  System.out.println(sb.toString()); | 
因为 AtomicReference 也是来自于 JDK 1.5 的 concurrent 的 API,所以用了早先线程安全的 StringBuffer 类。
本文链接 https://yanbin.blog/consolidate-use-of-java-future/, 来自 隔叶黄莺 Yanbin Blog
[版权声明]  本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。