線程池Executors詳解
為什麽要用線程池呢?
一是減少了創建和銷毀線程的次數,每個工作線程都可以被重復利用,可執行多個任務;
二是可以根據系統的承受能力,調整線程池中工作線線程的數目,防止因為因為消耗過多的內存,而把服務器累趴下(每個線程需要大約1MB內存,線程開的越多,消耗的內存也就越大,最後死機)。
線程池的基本思想是一種對象池的思想,開辟一塊內存空間,裏面存放了眾多(未死亡)的線程,池中線程執行調度由池管理器來處理。當有線程任務時,從池中取一個,執行完成後線程對象歸池,這樣可以避免反復創建線程對象所帶來的性能開銷,節省了系統的資源。
可見,線程池的作用主要是限制系統中執行線程的數量。 根據系統的環境情況,可以自動或手動設置線程數量,達到運行的最佳效果。這是因為,線程少了會浪費系統資源,線程多了會造成系統擁擠、效率不高。用線程池控制線程數量,其他線程排隊等候。一個任務執行完畢,再從隊列中取最前面的任務開始執行。若隊列中沒有等待進程,線程池的這一資源處於等待。當一個新任務需要運行時,如果線程池中有等待的工作線程,就可以開始運行了;否則進入等待隊列。
Java裏面線程池的頂級接口是Executor,但是嚴格意義上講Executor並不是一個線程池,而只是一個執行線程的工具。真正的線程池接口是ExecutorService。ThreadPoolExecutor是Executors類的底層實現。我們先介紹下Executors。
在使用線程池之前,必須知道如何去創建一個線程池。
1.固定大小的線程池
package com.itszt.test3; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 線程池 */ public class Test1 extends Object{ public static void main(String[] args) { //創建一個可重用,固定線程數的線程池 ExecutorService threadPool = Executors.newFixedThreadPool(2); //創建實現了Runnable接口的類,如Thread MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); MyThread t3 = new MyThread(); MyThread t4 = new MyThread(); //將線程放入池中執行 threadPool.execute(t1); threadPool.execute(t2); threadPool.execute(t3); threadPool.execute(t4); //關閉線程池 threadPool.shutdown(); } } class MyThread extends Thread{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"正在執行..."); } }
執行結果如下:
pool-1-thread-1正在執行... pool-1-thread-2正在執行... pool-1-thread-1正在執行... pool-1-thread-1正在執行...
2.單任務線程池
復用上述代碼,將上例中創建線程池的代碼改為:
ExecutorService threadPool = Executors.newSingleThreadExecutor();
執行結果如下:
pool-1-thread-1正在執行... pool-1-thread-1正在執行... pool-1-thread-1正在執行... pool-1-thread-1正在執行...
3.可變尺寸的線程池
改變創建線程池的方法:
ExecutorService threadPool = Executors.newCachedThreadPool();
執行結果如下:
pool-1-thread-2正在執行... pool-1-thread-1正在執行... pool-1-thread-3正在執行... pool-1-thread-4正在執行...
4.延遲連接池
修改創建線程池的方式:
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(2); MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); MyThread t3 = new MyThread(); MyThread t4 = new MyThread(); //延遲執行 threadPool.schedule(t1,5, TimeUnit.MILLISECONDS); threadPool.schedule(t2,5, TimeUnit.MILLISECONDS); threadPool.schedule(t3,5, TimeUnit.MILLISECONDS); threadPool.schedule(t4,5, TimeUnit.MILLISECONDS); //關閉線程池 threadPool.shutdown();
5.單任務延遲連接池
修改創建線程池的方式:
ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();
6.自定義線程池
package com.itszt.test3; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * 自定義線程池 */ public class Test2 { public static void main(String[] args) { //創建等待隊列 BlockingQueue bQueue = new ArrayBlockingQueue(20); //創建一個單線程執行程序,可安排在給定延遲時間後執行 ThreadPoolExecutor pool = new ThreadPoolExecutor(2,3,2,TimeUnit.MILLISECONDS,bQueue); //創建實現了Runnable接口的類,如Thread MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); MyThread t3 = new MyThread(); MyThread t4 = new MyThread(); //將線程放入池中執行 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); //關閉線程池 pool.shutdown(); } } class MyThread extends Thread{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"正在執行..."+System.currentTimeMillis()); } }
線程池Executors詳解