JDK8-11-CompletableFuture(3)- 異常處理,completeExceptionally使用(如何讓主線程捕獲其他線程產(chǎn)生的異常)
JDK8-11-CompletableFuture(3)- 異常處理
承接上文
對(duì)之前例子中的 calculatePrice 方法進(jìn)行些許改造,當(dāng)product傳入空值時(shí)拋出“無(wú)效商品” 的異常:
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("無(wú)效的商品");
}
return random.nextDouble() * product.charAt(0);
}
public Future<Double> getPriceAsync(String product) {
//創(chuàng)建 CompletableFuture 對(duì)象,對(duì)象中包含異步計(jì)算結(jié)果
CompletableFuture<Double> futurePrice = new CompletableFuture<>();
//新建線程計(jì)算商品價(jià)格
new Thread(() -> {
double price = calculatePrice(product);
//將異步計(jì)算得到的結(jié)果設(shè)置到 CompletableFuture 中,
futurePrice.complete(price);
}).start();
//無(wú)需等待計(jì)算結(jié)果,直接返回 CompletableFuture 對(duì)象
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("耗時(shí):" + (System.currentTimeMillis() - start));
}
public static void main(String[] args) {
getPriceAsyncTest(null);
}
}
運(yùn)行結(jié)果:

image.png
注意看,由于傳入空名稱的產(chǎn)品,程序產(chǎn)生異常,產(chǎn)生異常的線程名為 Thread-0,而程序并沒有結(jié)束,主線程任然阻塞在 get 方法這里,如果不進(jìn)行其他處理,程序會(huì)一直阻塞
completeExceptionally 方法使用
主線程可以使用有超時(shí)時(shí)間參數(shù)的重載get方法來(lái)避免一直阻塞,雖然這是一種推薦并且有用的做法,但是這樣主線程并不能得知產(chǎn)生超時(shí)異常的具體原因
下面通過(guò)改造 getPriceAsync 方法讓主線程可以捕獲其他線程產(chǎn)生的異常,具體如下:
在 calculatePrice 方法調(diào)用處加上try/catch,并調(diào)用
futurePrice.completeExceptionally(e);
public Future<Double> getPriceAsync(String product) {
//創(chuàng)建 CompletableFuture 對(duì)象,對(duì)象中包含異步計(jì)算結(jié)果
CompletableFuture<Double> futurePrice = new CompletableFuture<>();
//新建線程計(jì)算商品價(jià)格
new Thread(() -> {
try {
double price = calculatePrice(product);
//將異步計(jì)算得到的結(jié)果設(shè)置到 CompletableFuture 中,
futurePrice.complete(price);
} catch (Exception e) {
futurePrice.completeExceptionally(e);
}
}).start();
//無(wú)需等待計(jì)算結(jié)果,直接返回 CompletableFuture 對(duì)象
return futurePrice;
}
再看程序執(zhí)行結(jié)果:
產(chǎn)生 ExecutionException 異常,說(shuō)明 Thread-0 線程產(chǎn)生的異常已經(jīng)被主線程捕獲

image.png