tutorial site1
tutorial site2html
每啓動一個新線程都會有相應的性能開銷(涉及到OS的交互:建立線程,銷燬線程),並且每一個線程都須要給棧分配一些內存等等。這種代價隨着新線程不斷的建立,將會大大下降性能甚至使JVM崩潰。java
如何解決?
使線程能夠複用,執行完一個任務,並不被銷燬,而是能夠繼續執行其餘的任務。這樣避免了建立以及銷燬線程的代價以及線程過多形成內存消耗過分以及切換過分問題。緩存
線程池(Thread Pool)的引入就是:限制應用程序中同一時刻運行的線程數
。根據系統的環境,能夠手動或者自動設置線程數量,達到最佳效果。服務器
能夠把併發執行的任務傳遞給一個線程池,來替代爲每一個併發執行的任務都啓動一個新的線程。只要池裏有空閒的線程,任務就會分配給一個線程執行。 在線程池的內部,任務被插入一個阻塞隊列
(任務隊列), 線程池的線程會去取這個隊列的任務。當一個新任務插入隊列時,一個空閒線程就會成功的從隊列中取出任務並執行它。網絡
線程池常常應用在多線程服務器上。每一個經過網絡到達服務器的鏈接都被包裝成一個任務而且傳遞給線程池。線程池的線程會併發的處理鏈接上的請求。Java 5 在 java.util.concurrent 包中自帶了內置的線程池,因此你不用非得實現本身的線程池。多線程
線程池的做用:
合理利用線程池可以帶來三個好處。
第一:下降資源消耗。經過重複利用已建立的線程下降線程建立和銷燬形成的消耗。
第二:提升響應速度。當任務到達時,任務能夠不須要等到線程建立就能當即執行。
第三:提升線程的可管理性。線程是稀缺資源,若是無限制的建立,不只會消耗系統資源,還會下降系統的穩定性,使用線程池能夠進行統一的分配,調優和監控。可是要作到合理的利用線程池,必須對其原理了如指掌。併發
線程池實現了系統中線程的數量。
根據系統的環境狀況,能夠自動或手動設置線程數量,達到運行的最佳效果;少了浪費了系統資源,多了形成系統擁擠效率不高。用線程池控制線程數量,其餘線程排隊等候。一個任務執行完畢,再從隊列的中取最前面的任務開始執行。若隊列中沒有等待進程,線程池的這一資源處於等待。當一個新任務須要運行時,若是線程池中有等待的工做線程,就能夠開始運行了;不然進入等待隊列。ide
JUC 包,線程池頂級接口是Executor. 可是嚴格意義講Executor並非一個線程。 而只是一個執行線程的工具。真正的線程池的接口是ExecutorService.工具
ExecutorService | 真正的線程池的接口 |
---|---|
ScheduledExecutorService | 能和Timer/TimerTask相似,解決那些須要任務重複執行的問題 |
ThreadPoolExecutor | ExecutorService的默認實現 |
ScheduledThreadPoolExecutor | 繼承 ThreadPoolExecutor 的 ScheduledExecutorService 接口實現,週期性任務調度的類實現 |
要配置一個線程池是比較複雜的,尤爲是對於線程池的原理不是很清楚的狀況下,頗有可能配置的線程池不是較優的,所以在 Executors 類裏面提供了一些靜態工廠
,生成一些經常使用的線程池。
1. newSingleThreadExecutor()
建立一個單線程的線程池。這個線程池只有一個線程在工做,也就是至關於單線程串行執行全部任務。若是這個惟一的線程由於異常結束,那麼會有一個新的線程來替代它。此線程池保證全部任務的執行順序按照任務的提交順序執行。性能
javapublic classMyThread extends Thread { publicvoid run() { System.out.println(Thread.currentThread().getName() + " 正在執行。。。"); } } public classTestSingleThreadExecutor { public static void main(String[] args) { // 建立一個可重用固定線程數的線程池 ExecutorService pool = Executors.newSingleThreadExecutor(); // 建立實現了 Runnable 接口對象,Thread 對象固然也實現了 Runnable 接口 Thread t1 = new MyThread(); Thread t2 = new MyThread(); Thread t3 = new MyThread(); Thread t4 = new MyThread(); Thread t5 = new MyThread(); // 將線程放入池中進行執行 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); // 關閉線程池 pool.shutdown(); } }
2.newFixedThreadPool()
建立固定大小的線程池。每次提交一個任務就建立一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,若是某個線程由於執行異常而結束,那麼線程池會補充一個新線程。
javapublicclass TestFixedThreadPool { publicstaticvoid main(String[] args) { // 建立一個可重用固定線程數的線程池 ExecutorService pool = Executors.newFixedThreadPool(2); // 建立實現了 Runnable 接口對象,Thread 對象固然也實現了 Runnable 接口 Thread t1 = new MyThread(); Thread t2 = new MyThread(); Thread t3 = new MyThread(); Thread t4 = new MyThread(); Thread t5 = new MyThread(); // 將線程放入池中進行執行 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); // 關閉線程池 pool.shutdown(); } }
javapublicclass TestCachedThreadPool { publicstaticvoid main(String[] args) { // 建立一個可重用固定線程數的線程池 ExecutorService pool = Executors.newCachedThreadPool(); // 建立實現了 Runnable 接口對象,Thread 對象固然也實現了 Runnable 接口 Thread t1 = new MyThread(); Thread t2 = new MyThread(); Thread t3 = new MyThread(); Thread t4 = new MyThread(); Thread t5 = new MyThread(); // 將線程放入池中進行執行 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); // 關閉線程池 pool.shutdown(); } }
4.newScheduledThreadPool
建立一個大小無限的線程池。此線程池支持定時以及週期性執行任務的需求。
javapublicclass TestScheduledThreadPoolExecutor { publicstaticvoid main(String[] args) { ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1); exec.scheduleAtFixedRate(new Runnable() {// 每隔一段時間就觸發異常 @Override publicvoid run() { //throw new RuntimeException(); System.out.println("================"); } }, 1000, 5000, TimeUnit.MILLISECONDS); exec.scheduleAtFixedRate(new Runnable() {// 每隔一段時間打印系統時間,證實二者是互不影響的 @Override publicvoid run() { System.out.println(System.nanoTime()); } }, 1000, 2000, TimeUnit.MILLISECONDS); } }