咱們使用線程的時候就去建立一個線程,這樣實現起來很是簡便,可是就會有一個問題: 若是併發的線程數量不少,而且每一個線程都是執行一個時間很短的任務就結束了,這樣頻繁建立線程就會大大下降 系統的效率,由於頻繁建立線程和銷燬線程須要時間。那麼有沒有一種辦法使得線程能夠複用,就是執行完一個任務,並不被銷燬,而是能夠繼續執行其餘的任務? 在Java中能夠經過線程池來達到這樣的效果。java
線程池:其實就是一個容納多個線程的容器,其中的線程能夠反覆使用,省去了頻繁建立線程對象的操做, 無需反覆建立線程而消耗過多資源。服務器
因爲線程池中有不少操做都是與優化資源相關的,咱們在這裏就很少贅述。咱們經過一張圖來了解線程池的工做原 理:併發
合理利用線程池可以帶來三個好處:dom
1. 下降資源消耗。減小了建立和銷燬線程的次數,每一個工做線程均可以被重複利用,可執行多個任務。ide
2. 提升響應速度。當任務到達時,任務能夠不須要的等到線程建立就能當即執行。工具
3. 提升線程的可管理性。能夠根據系統的承受能力,調整線程池中工做線線程的數目,防止由於消耗過多的內 存,而把服務器累趴下(每一個線程須要大約1MB內存,線程開的越多,消耗的內存也就越大,最後死機)。測試
Java裏面線程池的頂級接口是 java.util.concurrent.Executor ,可是嚴格意義上講 Executor 並非一個線 程池,而只是一個執行線程的工具。真正的線程池接口是 java.util.concurrent.ExecutorService 。 要配置一個線程池是比較複雜的,尤爲是對於線程池的原理不是很清楚的狀況下,頗有可能配置的線程池不是較優 的,所以在 java.util.concurrent.Executors 線程工廠類裏面提供了一些靜態工廠,生成一些經常使用的線程池。 官方建議使用Executors工程類來建立線程池對象。 Executors類中有個建立線程池的方法以下:優化
public static ExecutorService newFixedThreadPool(int nThreads) :返回線程池對象。(建立的是 有界線程池,也就是池中的線程個數能夠指定最大數量)線程
獲取到了一個線程池ExecutorService 對象,那麼怎麼使用呢,在這裏定義了一個使用線程池對象的方法以下: public Future submit(Runnable task) :獲取線程池中的某一個線程對象,並執行code
Future接口:用來記錄線程任務執行完畢後產生的結果。
使用線程池中線程對象的步驟:
1. 建立線程池對象。
2. 建立Runnable接口子類對象。(task)
3. 提交Runnable接口子類對象。(take task)
4. 關閉線程池(通常不作)。
Runnable實現類代碼:
public class MyRunnable implements Runnable { @Override public void run() { System.out.println("我要一個教練"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("教練來了: " + Thread.currentThread().getName()); System.out.println("教我游泳,交完後,教練回到了游泳池"); } }
線程池測試類:
public class Demo01ThreadPool { public static void main(String[] args) { // 建立線程池對象 ExecutorService service = Executors.newFixedThreadPool(2);//包含2個線程對象 // 建立Runnable實例對象 MyRunnable r = new MyRunnable(); //本身建立線程對象的方式 // Thread t = new Thread(r); // t.start(); ---> 調用MyRunnable中的run() // 從線程池中獲取線程對象,而後調用MyRunnable中的run() service.submit(r); // 再獲取個線程對象,調用MyRunnable中的run() service.submit(r); service.submit(r); // 注意:submit方法調用結束後,程序並不終止,是由於線程池控制了線程的關閉。 // 將使用完的線程又歸還到了線程池中 // 關閉線程池 //service.shutdown(); } }
Callable測試代碼:
Future submit(Callable task) : 獲取線程池中的某一個線程對象,並執行.
Future : 表示計算的結果.
V get() : 獲取計算完成的結果。
public class Demo02ThreadPool { public static void main(String[] args) throws Exception { // 建立線程池對象 ExecutorService service = Executors.newFixedThreadPool(2);//包含2個線程對象 // 建立Runnable實例對象 Callable<Double> c = new Callable<Double>() { @Override public Double call() throws Exception { return Math.random(); } }; // 從線程池中獲取線程對象,而後調用Callable中的call() Future<Double> f1 = service.submit(c); // Futur 調用get() 獲取運算結果 System.out.println(f1.get()); Future<Double> f2 = service.submit(c); System.out.println(f2.get()); Future<Double> f3 = service.submit(c); System.out.println(f3.get()); } }