并发 && 并行
同步API && 异步API
Future
public interface Future<V> {
}
基本用法
通常只需要将耗时的操作封装在一个Callable
对象中,再将它提交给ExecutorService
就可以了。
ExecutorService executorService = Executors.newCachedThreadPool();
Future<Double> future = executorService.submit(new Callable<Double>() {
@Override
public Double call() throws Exception {
return null;
}
});
try {
Double res = future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
Future接口的局限性
有一些操作,使用Future中提供的方法并不足以编写简洁的并发代码,比如
- 将两个异步计算合并为一个——这个两个异步计算之间相互独立,同时第二个又依赖于第一个的结果
- 等待Future集合中的所有任务都完成
- 仅等待Future集合中最快结束的任务完成,并返回它的结果
- 通过编程方式完成一个Future任务的执行(即以手工设定异步操作结果的方式)
- 应对Future的完成事件(即当Future的完成事件发生时会收到通知,并能使用Future计算的结果进行下一步操作,不只是简单地阻塞等待操作的结果)
CompletableFuture
CompletableFuture
实现了Future<T>
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {}
使用示例
public class Shop {
public double getPrice(String product){
return calculatePrice(product);
}
private double calculatePrice(String product){
delay();
Random random = new Random();
return random.nextDouble() * product.charAt(0) + product.charAt(1);
}
public static void delay(){
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
将同步方法getPrice()转换为异步方法
public Future<Double> getPriceAsync(String product){
CompletableFuture<Double> futurePrice = new CompletableFuture<>();
new Thread(() -> {
double price = calculatePrice(product);
futurePrice.complete(price);
}).start();
return futurePrice;
}
CompletableFuture
类自身提供了大量的工厂方法
public Future<Double> getPriceAsyncBySupplyAsync(String product){
return CompletableFuture.supplyAsync(() -> calculatePrice(product));
}
supplyAsync
方法接受一个生产者作为参数,返回一个CompletableFuture
对象,该对象完成异步执行后会读取调用生产者方法的返回值。 这个方式和手工创建的是完全等价的。
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
return asyncSupplyStage(asyncPool, supplier);
}