1、Future接口
Future
接口在 Java 5 中被引入,设计初衷是对将来某个时刻会发生的结果进行建模。它建模了一种异步计算,返回一个执行运算结果的引用,当运算结束后,这个引用被返回给调用方。在Future
中触发那些潜在耗时的操作把调用线程解放出来,让它能继续执行其他有价值的工作,不需要等待耗时的操作完成。
示例:使用Future
以异步的方式执行一个耗时的操作:
ExecutorService executor = Executors.newCachedThreadPool();
Future<Double> future = executor.submit(new Callable<Double>() { //向ExecutorService提交一个Callable对象
public Double call() {
return doSomeLongComputation();//以异步方式在新线程中执行耗时的操作
}
});
doSomethingElse();
try {
Double result = future.get(1, TimeUnit.SECONDS);//获取异步操作结果,如果被阻塞,无法得到结果,在等待1秒钟后退出
} catch (ExecutionException ee) {
// 计算抛出一个异常
} catch (InterruptedException ie) {
// 当前线程在等待过程中被中断
} catch (TimeoutException te) {
// 在Future对象完成之前超时
}
这种编程方式让你的线程可以在ExecutorService
以并发方式调用另一个线程执行耗时操作的同时,去执行一些其他任务。如果已经运行到没有异步操作的结果就无法继续进行时,可以调用它的get
方法去获取操作结果。如果操作已经完成,该方法会立刻返回操作结果,否则它会阻塞线程,直到操作完成,返回相应的结果。
为了处理长时间运行的操作永远不返回的可能性,虽然Future
提供了一个无需任何参数的get
方法,但还是推荐使用重载版本的get
方法,它接受一个超时的参数,可以定义线程等待Future结果的时间,而不是永无止境地等待下去。
Future
接口的局限性:Future
接口提供了方法来检测异步计算是否已经结束(使用isDone
方法),等待异步操作结束,以及获取计算的结果。但这些特性还不足以让你编写简洁的并发代码。
1、将两个异步计算合并为一个,这两个异步计算之间相互独立,同时第二个又依赖于第一个的结果。
2、等待Future
集合中的所有任务都完成。
3、仅等待Future
集合中快结束的任务完成,并返回它的结果。
4、通过编程方式完成一个Future
任务的执行。
5、应对Future
的完成事件(即当Future
的完成事件发生时会收到通知,并能使用Future
计算的结果进行下一步操作,不只是简单地阻塞等待操作结果)。
2、CompletableFuture
CompletableFuture
类提供了大量精巧的工厂方法,使用这些方法能更容易地完成整个流程,不用担心实现细节。
2.1 无返回值的 runAsync 异步回调
public class CompletableFutureTest {
public static void main(String[] args) throws Exception {
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "runAsync=>Void");
});
System.out.println("1111");
completableFuture.get();
}
}
2.2 有返回值的 supplyAsync 异步回调
public class CompletableFutureTest {
public static void main(String[] args) throws Exception {
CompletableFuture<Integer> completableFuture =
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "supplyAsync=>Integer");
int i = 10 / 0;
return 1024;
});
System.out.println(completableFuture.whenComplete((t, u) -> {
System.out.println("t=>" + t); // 正常的返回结果
System.out.println("u=>" + u); // 错误信息:java.util.concurrent.CompletionException:java.lang.ArithmeticException: /byzero
}).exceptionally((e) -> {
System.out.println(e.getMessage());
return 233; // 可以获取到错误的返回结果
}).get());
}
}