JDK8-11-CompletableFuture(3)- 异常处理,completeExceptionally使用(如何让主线程捕获其他线程产生的异常)
JDK8-11-CompletableFuture(3)- 异常处理
承接上文
对之前例子中的 calculatePrice 方法进行些许改造,当product传入空值时抛出“无效商品” 的异常:
public class Shop2 {
private static final Random random = new Random();
public double calculatePrice(String product) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (product== null || "".equals(product)) {
throw new RuntimeException("无效的商品");
}
return random.nextDouble() * product.charAt(0);
}
public Future<Double> getPriceAsync(String product) {
//创建 CompletableFuture 对象,对象中包含异步计算结果
CompletableFuture<Double> futurePrice = new CompletableFuture<>();
//新建线程计算商品价格
new Thread(() -> {
double price = calculatePrice(product);
//将异步计算得到的结果设置到 CompletableFuture 中,
futurePrice.complete(price);
}).start();
//无需等待计算结果,直接返回 CompletableFuture 对象
return futurePrice;
}
public static void getPriceAsyncTest(String product) {
long start = System.currentTimeMillis();
Future<Double> priceFuture = new Shop2().getPriceAsync(product);
System.out.println(Thread.currentThread() + " 开始做其他事情。。。");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
System.out.println(priceFuture.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("耗时:" + (System.currentTimeMillis() - start));
}
public static void main(String[] args) {
getPriceAsyncTest(null);
}
}
运行结果:
注意看,由于传入空名称的产品,程序产生异常,产生异常的线程名为 Thread-0,而程序并没有结束,主线程任然阻塞在 get 方法这里,如果不进行其他处理,程序会一直阻塞
completeExceptionally 方法使用
主线程可以使用有超时时间参数的重载get方法来避免一直阻塞,虽然这是一种推荐并且有用的做法,但是这样主线程并不能得知产生超时异常的具体原因
下面通过改造 getPriceAsync 方法让主线程可以捕获其他线程产生的异常,具体如下:
在 calculatePrice 方法调用处加上try/catch,并调用
futurePrice.completeExceptionally(e);
public Future<Double> getPriceAsync(String product) {
//创建 CompletableFuture 对象,对象中包含异步计算结果
CompletableFuture<Double> futurePrice = new CompletableFuture<>();
//新建线程计算商品价格
new Thread(() -> {
try {
double price = calculatePrice(product);
//将异步计算得到的结果设置到 CompletableFuture 中,
futurePrice.complete(price);
} catch (Exception e) {
futurePrice.completeExceptionally(e);
}
}).start();
//无需等待计算结果,直接返回 CompletableFuture 对象
return futurePrice;
}
再看程序执行结果:
产生 ExecutionException 异常,说明 Thread-0 线程产生的异常已经被主线程捕获