Future和FutureTask
在Java的早期版本中,查詢運行中的線程狀態,以及使線程在執行之後返回一個值是非常困難的。由於run(運行)方法返回void,你必須編寫大量的代碼從線程中返回一個值。使用過這種方法的程序員肯定了解其痛苦的經歷。
你可以使用Future接口或者FutureTask類從異步執行的線程中得到一個返回值。Future接口提供了檢查計算過程是否完成、檢索計算結果或終止計算過程的一些方法。FutureTask類提供了Future接口方法的基本實現(implementation)。只有計算過程完成以後才能檢索結果;假如計算過程沒有完成,get方法會被阻塞(block)。
下載代碼中的MyStringReverser.java文件演示了FutureTask類的使用,並提供了一個輕易理解的示例。它以每秒鐘一個字符的速度從後向前顯示提交的字符串,同時主線程檢測事務是否完成了:
while(!future.isDone()){
System.out.println("Task not yet completed.");
try{
Thread.currentThread().sleep(500);
}catch(InterruptedException ie){
System.out.println("Will check after 1/2 sec.");
}
}
在事務完成以後,就使用get方法從Future對象中檢索結果:
System.out.println("Here is result..."+future.get());
ThreadPoolExecutor(線程池執行器)
有了ThreadPoolExecutor類之後你可以編寫自己的服務器了。這個類為配置和調整服務器提供了很多的特性,與很多大規模的企業級EJB服務器相似。下面是它的一些配置參數:
· 核心和最大的線程池大小
通過把corePoolSize和maximumPoolSize設置為相同的值,你就可以建立一個大小固定的線程池了。通過把maximumPoolSize設置為一個極大的值(例如Integer.MAX_VALUE),你就可以答應線程池容納任意數量的並發事務了。
· 根據需要構造
在默認情況下,只有在新事務要求的時候,ThreadPoolExecutor才開始建立和啟動核心的線程,但是你可以使用prestartCoreThread或prestartAllCoreThreads動態地重載它。
· 保持活動的時間
假如線程池中當前線程的數量超過了corePoolSize,那麼這些超過的線程的空閒時間大於keepAliveTime的時候,它們就會被終止。
· 排隊
排隊遵循下面的規則:
· 假如正在運行的線程數量少於corePoolSize,Executor總會添加新線程而不會排隊。
· 假如corePoolSize或更多數量的線程在運行,Executor總會對請求進行排隊而不會添加新線程。
· 假如某個請求不能參與排隊,就會建立新線程,除非線程數量超過了maximumPoolSize(在超過的情況下,該事務會被拒絕)。
· Hook方法
這個類提供了beforeExecute()和afterExecute() hook方法,它們分別在每個事務執行之前和之後被調用。為了使用它們,你必須建立這個類的子類(因為這些方法是受保護的)。
下載代碼中的MyThreadPoolExecutor.java提供了一些監視多種配置參數的具體示例。你可以發現隨著每個事務的增加和完成,線程池和隊列大小在不斷變化。你可以修改代碼中的設置信息。 並發集合
JDK 1.5提供了下面一些集合實現,它們是被設計為用於多線程環境的:
· ConcurrentHashMap
· CopyOnWriteArrayList
· CopyOnWriteArraySet
ConcurrentHashMap類為檢索和更新(update)可調整的預期的並發性提供了完整的線程安全的(thread-safe)並發性支持。CopyOnWriteArraySet是一組線程安全的變量集合,CopyOnArrayList是一個線程安全的數組列表(ArrayList)變量。在修改原始的數組或集合之前,它們中的每一個都會把下層的數組或集合復制一份。其結果是,讀取的速度很快,而更新的速度很慢。