前言:
异步操作一直是编程领域不可避免的问题,我们在进行网络请求等耗时操作时必然需要采用异步处理来避免主线程的阻塞!在Java1.5之前甚至现在为止中我们都习惯用Thread来解决问题,而准备过Java面试的同学应该都知道开启线程除了Runable还可以使用Callable来实现。而Callable就是与Future配合使用的。
首先看下简单的Future用法
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
Thread.sleep(1000);
System.out.println("耗时任务执行完成!");
return 200;
}
};
FutureTask<Integer> integerFutureTask = new FutureTask<>(callable);
Thread thread = new Thread(integerFutureTask);
thread.start();
}
try {
//异步获取返回值,未返回阻塞直到获取结果
Integer integer = integerFutureTask.get();
//可以添加获取超时
Integer result = integerFutureTask.get(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
当看到前一段代码时,你一定受不了了,因为比Runable还多了一行代码嘞!浪费我时间!!!当再往下看你就知道了Runable与Callable的主要区别了,Callable是可以获取返回值的,这就是异步!!!异步的意义在于我们可以在 integerFutureTask.get()这个方法执行之前去完成其他任务充分利用cpu,注意:这个get方法使用时如果Callable中耗时操作没有结束还是同步阻塞直到返回结果的!
CompletableFuture
CompletableFuture是Java1.8的产物,1.8版本最大的改动就是提出了流式编程和lambda。简单的来说,CompletableFuture就是使用1.8的思想改进了Future,不需要使用Callable、FutureTask这些繁琐的操作了,示例如下:
CompletableFuture<Integer> completableFuture = new CompletableFuture<>();
new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
completableFuture.complete(200);
}).start();
try {
//异步获取结果
Integer integer = completableFuture.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
还有更简化的操作
CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 200;
});
Integer result1 = completableFuture1.get();
//也可以使用join,它不会抛出异常,不显得臃肿
Integer result2 = completableFuture1.join();
最后
CompletableFuture简化了异步操作,我们还可以配置线程来实现耗时操作的并发执行,十分方便,有兴趣的同学可以看这一篇//www.greatytc.com/p/908a11b4b39d