創建線程以及管理線程池基本理解
參考原文鏈接:http://www.oschina.net/question/12_11255?sort=time
一、創建一個簡單的java線程
在 Java 語言中,一個最簡單的線程如下代碼所示:
- Runnable runnable = new Runnable(){
- public void run(){
- System.out.println("Run");
- }
- }
可通過下面一行代碼來啟動這個線程:
new Thread(runnable).start();
這是一個再簡單不過的例子了,但如果你有許多需要長時間運行的任務同時執行,並需要等所有的這些線程都執行完畢,還想得到一個返回值,那么這就有點小小難度了。但 Java 已經有解決方案給你,那就是 Executors ,一個簡單的類可以讓你創建線程池和線程工廠。
二、Executors創建線程池
一個線程池使用類 ExecutorService 的實例來表示,通過 ExecutorService 你可以提交任務,並進行調度執行。下面列舉一些你可以通過 Executors 類來創建的線程池的類型:
1.Single Thread Executor : 只有一個線程的線程池,因此所有提交的任務是順序執行,代碼:
- Executors.newSingleThreadExecutor()
2.Cached Thread Pool : 線程池里有很多線程需要同時執行,老的可用線程將被新的任務觸發重新執行,如果線程超過60秒內沒執行,那么將被終止並從池中刪除,代碼:
- Executors.newCachedThreadPool()
3.Fixed Thread Pool : 擁有固定線程數的線程池,如果沒有任務執行,那么線程會一直等待,代碼:
- Executors.newFixedThreadPool()
4.Scheduled Thread Pool : 用來調度即將執行的任務的線程池,代碼:
- Executors.newScheduledThreadPool()
5.Single Thread Scheduled Pool : 只有一個線程,用來調度執行將來的任務,代碼:
- Executors.newSingleThreadScheduledExecutor()
三、主線程等待子線程結束各種方式
一旦你創建了一個線程池,你就可以往池中通過不同的方法提交執行任務,可提交 Runnable 或者 Callable 到線程池中,該方法返回一個 Future 實例表示任務的狀態,如果你提交一個 Runnable ,那么如果任務完成后 Future 對象返回 null。
例如,你編寫下面的 Callable:
- private final class StringTask extends Callable<String>{
- public String call(){
- //Long operations
- return "Run";
- }
- }
如果你想使用4個線程來執行這個任務10次,那么代碼如下:
ExecutorService pool = Executors.newFixedThreadPool(4);
for(int i = 0; i < 10; i++){
pool.submit(new StringTask());
}
但你必須手工的關閉線程池來結束所有池中的線程:
pool.shutdown();
如果你不這么做,JVM 並不會去關閉這些線程;另外你可以使用 shutdownNow() 的方法來強制關閉線程池,那么執行中的線程也會被中斷,所有尚未被執行的任務也將不會再執行。
但這個例子中,你無法獲取任務的執行狀態,因此我們需要借助 Future 對象:
下面的例子同時可以阻塞主線程等待子線程完成,但是該方式,如果阻塞的第一個線程很久,可能其他線程已經執行完了,很多情況不太適用
- ExecutorService pool = Executors.newFixedThreadPool(4);
- List<Future<String>> futures = new ArrayList<Future<String>>(10);
- for(int i = 0; i < 10; i++){
- futures.add(pool.submit(new StringTask()));
- }
- for(Future<String> future : futures){
- String result = future.get();
- //Compute the result
- }
- pool.shutdown();
不過這段代碼稍微有點復雜,而且有不足的地方。如果第一個任務耗費非常長的時間來執行,然后其他的任務都早於它結束,那么當前線程就無法在第一個任務結束之前獲得執行結果,但是別着急,Java 為你提供了解決方案——CompletionService。
一個 CompletionService 就是一個服務,用以簡化等待任務的執行結果,實現的類是 ExecutorCompletionService,該類基於 ExecutorService,因此我們可試試下面的代碼:
- ExecutorService threadPool = Executors.newFixedThreadPool(4);
- CompletionService<String> pool = new ExecutorCompletionService<String>(threadPool);
- for(int i = 0; i < 10; i++){
- pool.submit(new StringTask());
- }
- for(int i = 0; i < 10; i++){
- String result = pool.take().get();
- //Compute the result
- }
- threadPool.shutdown();
通過這段代碼,我們可以根據執行結束的順序獲取對應的結果,而無需維護一個 Future 對象的集合。
這就是本文的全部,通過 Java 為我們提供的各種工具,可以方便的進行多任務的編程,通過使用 Executors、ExecutorService 以及 CompletionService 等工具類,我們可以創建復雜的並行任務執行算法,而且可以輕松改變線程數。
http://825635381.iteye.com/blog/2184605