java中Future的使用
Future是java 1.5引入的一個(gè)interface酗昼,可以方便的用于異步結(jié)果的獲取。 本文將會(huì)通過(guò)具體的例子講解如何使用Future梳猪。
創(chuàng)建Future
正如上面所說(shuō)麻削,F(xiàn)uture代表的是異步執(zhí)行的結(jié)果,意思是當(dāng)異步執(zhí)行結(jié)束之后春弥,返回的結(jié)果將會(huì)保存在Future中呛哟。
那么我們什么時(shí)候會(huì)用到Future呢? 一般來(lái)說(shuō)匿沛,當(dāng)我們執(zhí)行一個(gè)長(zhǎng)時(shí)間運(yùn)行的任務(wù)時(shí)扫责,使用Future就可以讓我們暫時(shí)去處理其他的任務(wù),等長(zhǎng)任務(wù)執(zhí)行完畢再返回其結(jié)果逃呼。
經(jīng)常會(huì)使用到Future的場(chǎng)景有:1. 計(jì)算密集場(chǎng)景鳖孤。2. 處理大數(shù)據(jù)量。3. 遠(yuǎn)程方法調(diào)用等抡笼。
接下來(lái)我們將會(huì)使用ExecutorService來(lái)創(chuàng)建一個(gè)Future苏揣。
<T> Future<T> submit(Callable<T> task);
上面是ExecutorService中定義的一個(gè)submit方法,它接收一個(gè)Callable參數(shù)蔫缸,并返回一個(gè)Future腿准。
我們用一個(gè)線程來(lái)計(jì)算一個(gè)平方運(yùn)算:
private ExecutorService executor
= Executors.newSingleThreadExecutor();
public Future<Integer> calculate(Integer input) {
return executor.submit(() -> {
System.out.println("Calculating..."+ input);
Thread.sleep(1000);
return input * input;
});
}
submit需要接受一個(gè)Callable參數(shù),Callable需要實(shí)現(xiàn)一個(gè)call方法,并返回結(jié)果吐葱。這里我們使用lamaba表達(dá)式來(lái)簡(jiǎn)化這一個(gè)流程街望。
從Future獲取結(jié)果
上面我們創(chuàng)建好了Future,接下來(lái)我們看一下怎么獲取到Future的值弟跑。
FutureUsage futureUsage=new FutureUsage();
Future<Integer> futureOne = futureUsage.calculate(20);
while(!futureOne.isDone()) {
System.out.println("Calculating...");
Thread.sleep(300);
}
Integer result = futureOne.get();
首先我們通過(guò)Future.isDone() 來(lái)判斷這個(gè)異步操作是否執(zhí)行完畢灾前,如果完畢我們就可以直接調(diào)用futureOne.get()來(lái)獲得Futre的結(jié)果。
這里futureOne.get()是一個(gè)阻塞操作孟辑,會(huì)一直等待異步執(zhí)行完畢才返回結(jié)果哎甲。
如果我們不想等待,future提供了一個(gè)帶時(shí)間的方法:
Integer result = futureOne.get(500, TimeUnit.MILLISECONDS);
如果在等待時(shí)間結(jié)束的時(shí)候饲嗽,F(xiàn)uture還有返回炭玫,則會(huì)拋出一個(gè)TimeoutException。
取消Future
如果我們提交了一個(gè)異步程序貌虾,但是想取消它吞加, 則可以這樣:
uture<Integer> futureTwo = futureUsage.calculate(4);
boolean canceled = futureTwo.cancel(true);
Future.cancel(boolean) 傳入一個(gè)boolean參數(shù),來(lái)選擇是否中斷正在運(yùn)行的task尽狠。
如果我們cancel之后衔憨,再次調(diào)用get()方法,則會(huì)拋出CancellationException袄膏。
多線程環(huán)境中運(yùn)行
如果有兩個(gè)計(jì)算任務(wù)践图,先看下在單線程下運(yùn)行的結(jié)果。
Future<Integer> future1 = futureUsage.calculate(10);
Future<Integer> future2 = futureUsage.calculate(100);
while (!(future1.isDone() && future2.isDone())) {
System.out.println(
String.format(
"future1 is %s and future2 is %s",
future1.isDone() ? "done" : "not done",
future2.isDone() ? "done" : "not done"
)
);
Thread.sleep(300);
}
Integer result1 = future1.get();
Integer result2 = future2.get();
System.out.println(result1 + " and " + result2);
因?yàn)槲覀兺ㄟ^(guò)Executors.newSingleThreadExecutor()來(lái)創(chuàng)建的單線程池沉馆。所以運(yùn)行結(jié)果如下:
Calculating...10
future1 is not done and future2 is not done
future1 is not done and future2 is not done
future1 is not done and future2 is not done
future1 is not done and future2 is not done
Calculating...100
future1 is done and future2 is not done
future1 is done and future2 is not done
future1 is done and future2 is not done
100 and 10000
如果我們使用Executors.newFixedThreadPool(2)來(lái)創(chuàng)建一個(gè)多線程池码党,則可以得到如下的結(jié)果:
calculating...10
calculating...100
future1 is not done and future2 is not done
future1 is not done and future2 is not done
future1 is not done and future2 is not done
future1 is not done and future2 is not done
100 and 10000
本文的例子可以參考https://github.com/ddean2009/learn-java-concurrency/tree/master/future
更多教程請(qǐng)參考 flydean的博客