在許多應用中需要頻繁的創建許多生命周期很短的線程,如果用傳統方法的話就會造成大量的資源了浪費,java的設計者們考慮到了這點在java中加入了線程池這個特性,它負責管理大量的線程的創建銷毀等操作。
首先我們需要了解一個類:java.util.concurrent.Executors(執行器)
執行器類擁有大量的靜態工廠方法用於創建線程池
方法 | 描述 |
newCachedThreadPool | 必要時創建線程,處於空閑狀態的線程將被保留60秒 |
newFixedThreadPool | 擁有固定數量的線程,並且不會自動銷毀空閑狀態的線程 |
newSingleThreadExecutor | 該線程池僅有一個線程,會順序執行任務隊列 |
newScheduledThreadPool | 用於預約執行任務的固定線程池 |
newSingleThreadScheduledExecutor | 用於預約執行任務的單線程池 |
下面我們來詳細了解下這些線程池。
newCachedThreadPool:通過名稱,不難看出這個方法創建出的線程池,具有數量可變,並且在需要的時候會自動創建更多的線程,並且會自動銷毀線程。
newFixedThreadPool:此線程池與newCachedThreadPool構建出的線程池的主要區別是,線程池在數量上固定,如果任務數量達到上限的話,就會將多余任務加入任務隊列,等線程池空出線程時即可執行,這種線程池並不會銷毀空閑線程。
newSingleThreadExecutor:此方法創建出的線程池相較於其他兩個線程較為特殊,此方法創建出的線程數量僅僅為1,也就是說所有除了正在執行的任務外,其余任務均在任務隊列中,當線程中的任務執行完畢后,任務隊列的第一個任務進入線程開始執行。
newScheduledThreadPool與 newSingleThreadScheduledExecutor:這兩個方法創建出的線程池是用於預定執行的線程池,他們可以用於在初始化后延遲執行,或周期性的執行,兩種線程池大體相同,唯一的區別就是可同時執行的線程數量。
當你挑選完的線程池后就需要創建以及使用線程池:
大概步驟為以下3步:
(1)調用執行器類(Executors)的靜態方法來創建線程池
(2)調用線程池的submit方法提交Runnable或Callable對象
(3)當不需要添加更多的任務時,調用shutdown關閉入口
下面通過代碼來逐步操作:
1 //創建線程池對象
2 ExecutorService service = Executors.newCachedThreadPool(); 3 //創建一個用於遞增輸出i值的runnable對象
4 Runnable runnable = new Runnable() { 5 @Override 6 public void run() { 7 for (int i = 0; i < 400; i++) { 8 System.out.println(i); 9 } 10 } 11 }; 12 //調用線程池的submit方法傳入runnable(傳入的runnable將會自動執行)
13 service.submit(runnable); 14 service.submit(runnable); 15 //當不需要傳入更多的任務時調用shutdown方法來關閉入口
16 service.shutdown();
需要注意的是如果希望直接停止線程池的一切任務是無法通過shutdown來操作的,因為shutdown僅僅是關閉了入口,但是已經加入的任務還是會繼續執行的,這時我們可以調用線程池的shutdownNow方法來操作,shutdownNow的作用是用來關閉線程池的入口並且會嘗試終止所有當前線程池內的任務。
//用來關閉線程池入口以及終止所有正在執行的任務
service.shutdownNow();
service的submit方法會返回一個Future<?>類型的對象,然而這是一個怎樣的類型呢?讓我們來看一下api中的方法摘要:
從方法摘要中可以看出該對象用於在加入線程池以后能夠對此任務進行取消,查看狀態等操作,如果說在加入線程池以后有可能會取消此任務的話就需要,在submit的時候就需要保存好Future對象。
1 //保存Future<?>
2 Future<?> run2 = service.submit(runnable); 3
4 //用於查看是否已經執行完畢,返回類型為boolean
5 System.out.println(run2.isDone()); 6
7 //取消任務,如果需要中斷的話參數為true
8 run2.cancel(true);
關於線程池的簡單操作大概就有這些,關於線程池的更多信息還需要深入的研究,java的最大優點是開源,也就是說想要深入學習其原理最好的方法也就是查看源碼,我也會在后面補充上線程池的源碼分析,希望大家支持:-D。