在有些方法里, 比如登陸,一般需要順序調用多個系統功能才能完成初始化操作.
比如 安全校驗-》獲取用戶權限-》獲取用戶設置信息-》獲取系統字典 等等, 在某些EAI模式的應用里,這些調用可能都是遠程調用,每個調用時間可能從0.5秒到數秒不等, 這樣累計下來用戶一個登陸操作,在后臺處理時間可能就有3,4秒,加上網絡傳輸延時,會主觀上給用戶造成系統很慢的感覺。
在單個方法調用效率無法改進的前提下,一個簡單的辦法是將調用方式由串行改為并行,即以多個thread分別去完成方法調用,最后匯總。
在java 5以前,因為線程的特性限制,必須手工編碼實現線程完成狀態的調用檢查。
比如
// thread
public void run() {
......
finished = true;
}
public boolean isFinished() {
return finished;
}
// 以阻塞循環的方式檢查是否執行完畢
while(!remoteCall.isFinished()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
這樣的代碼是繁瑣,較低效率,也容易出錯的,尤其在線程多于2個的時候。而在服務器方代碼中過多的線程使用又可能會導致內存溢出和資源泄露。
今天翻書的時候發現java 5中的cucurrent包對此進行了改進 繼承自Callable 的類有能力將執行結果返回,并且可以自行檢查執行是否結束。
public class RandomPrimeSearch implements Callable<BigInteger> {
public BigInteger call( ) {
// do operation here
return BigInteger.probablePrime(bitSize, prng);
}
}
FutureTask<BigInteger> task = new FutureTask<BigInteger>(new RandomPrimeSearch(512)); //需要利用泛型模板返回處理結果
new Thread(task).start( );
BigInteger result = task.get( ); //此處會自動判斷是否執行結束,未結束會繼續等待。也可以設定最大等待時間
//為了提高效率 也可以使用service方式調用
ExecutorService service = Executors.newFixedThreadPool(5);
Future<BigInteger> prime1 = service.submit(new RandomPrimeSearch(512));
這樣一來,使用這種并發模式處理代碼就容易多了。程序可以簡單的修改為這樣的結構
remoateCall1 = doRemoteCall1(); // 啟動線程1 將方法處理以封裝到線程中
remoateCall2 = doRemoteCall2(); // 啟動線程2
remoteCall1.get().getUserSetting() ;
remoteCall2.get().getDictionaryList();
....
呵呵,基本和順序執行時差不多,代碼修改量比較小。
java 5中引入了線程執行服務ExecutorService 的概念以后, 如果以線程池的方式執行線程調用,資源消耗會大幅度減少,所以不用太擔心并發處理會產生過多的系統負荷。