程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 深入淺出多線程(3)-Future異步模式以及在JDK1.5Concurrent包中的實現

深入淺出多線程(3)-Future異步模式以及在JDK1.5Concurrent包中的實現

編輯:關於JAVA

接深入淺出多線程(2)在多線程交互的中,經常有一個線程需要得到另個一 線程的計算結果,我們常用的是Future異步模式來加以解決。

什麼是Future模式呢?Future 顧名思義,在金融行業叫期權,市場上有看跌 期權和看漲期權,你可以在現在(比如九月份)購買年底(十二月)的石油,假 如你買的是看漲期權,那麼如果石油真的漲了,你也可以在十二月份依照九月份 商定的價格購買。扯遠了,Future就是你可以拿到未來的結果。對於多線程,如 果線程A要等待線程B的結果,那麼線程A沒必要等待B,直到B有結果,可以先拿 到一個未來的Future,等B有結果是再取真實的結果。其實這個模式用的很多, 比如浏覽器下載圖片的時候,剛開始是不是通過模糊的圖片來代替最後的圖片, 等下載圖片的線程下載完圖片後在替換。如圖所示:

在沒有JDK1.5提供的Concurrent之前,我們通過自定義一個結果類,負責結 果持有。

如下面代碼:

package vincent.blogjava.net;
public class FutureResult {
private String result;
private boolean isFinish =false;
public String getResult() {
return result;
}
public synchronized void setResult(String result) {
this.result = result;
this.isFinish = true;
}
public synchronized boolean isFinish() {
return isFinish;
}
}

存儲結果值和是否完成的Flag。

package vincent.blogjava.net;
public class GenerateResultThread extends Thread{
FutureResult fr ;
public GenerateResultThread(FutureResult fr ){
this.fr = fr;
}
public void run(){
//模仿大量耗時計算後(5s)返回結果。
try {
System.out.println("GenerateResultThread開始進行計算了! ");
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
fr.setResult("ResultByGenerateResultThread");
}
}

計算具體業務邏輯並放回結果的線程。

package vincent.blogjava.net;
public class Main {
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
FutureResult fr = new FutureResult();
new GenerateResultThread(fr).start();
//main線程無需等待,不會被阻塞。
//模仿 干自己的活 2s。
Thread.sleep(2000);
// 估計算完了吧 取取試試。
System.out.println("過來2s了,看看有結果嗎?");
if(!fr.isFinish()){System.out.println("還沒有完成呢! 繼續干自己 活吧!");}
//模仿 干自己的活 4s。
Thread.sleep(4000);
System.out.println("過來4s了,看看有結果嗎?");
if(fr.isFinish()){
System.out.println("完成了!");
System.out.println("Result:"+fr.getResult());
}
}
}

Main方法需要GenerateResultThread線程計算的結果,通過這 種模式,main線程不需要阻塞。結果如下:

GenerateResultThread開始進行計算了!

過來2s了,看看有結果嗎?

還沒有完成呢! 繼續干自己活吧!

過來4s了,看看有結果嗎?

完成了!

Result:ResultByGenerateResultThread

在JDK1.5 Concurrent 中,提供了這種Callable的機制。我們只要實現 Callable接口中的Call方法,Call方法是可以返回任意類型的結果的。如下:

package vincent.blogjava.net;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
public class ConcurrentImpl {
public static void main(String[] args) throws InterruptedException, Exception {
FutureTask fr = new FutureTask(new Returnresult());
new Thread(fr).start();
//main線程無需等待,不會被阻塞。
//模仿 干自己的活 2s。
Thread.sleep(2000);
// 估計算完了吧 取取試試。
System.out.println("過來2s了,看看有結果嗎?");
if(!fr.isDone()){System.out.println("還沒有完成呢! 繼續干自己活 吧!");}
//模仿 干自己的活 4s。
Thread.sleep(4000);
System.out.println("過來4s了,看看有結果嗎?");
if(fr.isDone()){
System.out.println("完成了!");
System.out.println("Result:"+fr.get());
}
}
}
class Returnresult implements Callable{
@Override
public Object call() throws Exception {
//模仿大量耗時計算後(5s)返回結果。
System.out.println("GenerateResultThread開始進行計算了! ");
Thread.sleep(11000);
return "ResultByGenerateResultThread";
}
}

Returnresult 實現了Callable接口,在Call方法中實現業務邏 輯,並返回結果。在Main方法裡面,初始化FutureTask 並將該Task作為 Runnable加入Thread後,啟動線程。得到跟剛才相同的效果。

注意: 通過JDK標准的Future後,沒有必要增加額外的Object來只有Result ,更加簡單明了,同時FutureTask還提供了Cancel的功能,我們持有FutureTask 引用後可以Cancel該線程。通過get()取值是,如果結果還沒有返回,將會阻塞 Main線程。

其實JDK 實現Future模式的秘密就在FutureTask類裡:

FutureTask是實現了Future 和Runnable,對了就是Runnbale接口,我們就可 以把它構造到Thread裡,啟動執行了。

看看,當 new Thread(new FutureTask(new Callable())).start 時:

看圖:

G

get 方法取result值,FutureTask 提供Timeout 功能,如果超時,拋出異常 。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved