我們平時在寫程序中常常使用多線程來提高CPU以及其他資源的利用率,但是當CPU中的線程超過了CPU調度范圍時,我們的程序就會變得緩慢甚至出現死鎖導致程序卡死等現象。也有很多時候我們需要創建的線程量巨大,但是每個線程的執行時間卻相對較小,這樣在新啟線程和關閉線程的時候消耗的系統資源要比花在處理實際的用戶請求的時間和資源更多。除了創建和銷毀線程的開銷之外,活動的線程也消耗系統資源。在一個 JVM 裡創建太多的線程可能會導致系統由於過度消耗內存而用完內存或“切換過度”。
線程池的出現能較好的解決以上問題,線程池為線程生命周期開銷問題和資源不足問題提供了解決方案。通過對多個任務重用線程,線程創建的開銷被分攤到了多個任務上。其好處是,因為在請求到達時線程已經存在,所以無意中也消除了線程創建所帶來的延遲。這樣,就可以立即為請求服務,使應用程序響應更快。而且,通過適當地調整線程池中的線程數目,也就是當請求的數目超過某個阈值時,就強制其它任何新到的請求一直等待,直到獲得一個線程來處理為止,從而可以防止資源不足。
在使用線程池之前,必須知道如何去創建一個線程池,在Java5中,需要了解的是java.util.concurrent.Executors類的API,這個類提供了四種比較常用線程池。
MyThread類代碼
public class MyThread extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName() + "正在執行。。。"); } }
newCachedThreadPool() 是根據需求創建新線程的,需求多時,創建的就多,需求少時,JVM自己會慢慢的釋放掉多余的線程,它是一種可變尺寸的線程池。
import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CachedThreadPool { public static void main(String[] args) { ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); Thread t1 = new MyThread(); Thread t2 = new MyThread(); Thread t3 = new MyThread(); Thread t4 = new MyThread(); Thread t5 = new MyThread(); cachedThreadPool.execute(t1); cachedThreadPool.execute(t2); cachedThreadPool.execute(t3); cachedThreadPool.execute(t4); cachedThreadPool.execute(t5); // 關閉線程池 cachedThreadPool.shutdown(); } }
創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。新的線程加入後,如果正在運行的線程達到了上限,則會阻塞,直到有了空閒的線程來運行。他是定長尺寸的線程池。
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class FixedThreadPool { public static void main(String[] args) { ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); Thread t1 = new MyThread(); Thread t2 = new MyThread(); Thread t3 = new MyThread(); Thread t4 = new MyThread(); Thread t5 = new MyThread(); fixedThreadPool.execute(t1); fixedThreadPool.execute(t2); fixedThreadPool.execute(t3); fixedThreadPool.execute(t4); fixedThreadPool.execute(t5); // 關閉線程池 fixedThreadPool.shutdown(); } }
創建一個定長線程池,支持定時及周期性任務執行。延遲執行示例代碼如下:
import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ScheduledThredPool { public static void main(String[] args) { ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2); // 創建實現了Runnable接口對象,Thread對象當然也實現了Runnable接口 Thread t1 = new MyThread(); Thread t2 = new MyThread(); Thread t3 = new MyThread(); // 將線程放入池中進行執行 scheduledThreadPool.execute(t1); // 使用延遲執行風格的方法 scheduledThreadPool.schedule(t2, 1000, TimeUnit.MILLISECONDS); scheduledThreadPool.schedule(t3, 10, TimeUnit.MILLISECONDS); // 關閉線程池 scheduledThreadPool.shutdown(); } }
創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。示例代碼如下:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SingleThreadExecutor { public static void main(String[] args) { ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); Thread t1 = new MyThread(); Thread t2 = new MyThread(); Thread t3 = new MyThread(); Thread t4 = new MyThread(); Thread t5 = new MyThread(); singleThreadExecutor.execute(t1); singleThreadExecutor.execute(t2); singleThreadExecutor.execute(t3); singleThreadExecutor.execute(t4); singleThreadExecutor.execute(t5); // 關閉線程池 singleThreadExecutor.shutdown(); } }
以上四中線程池分別運用於不同場景,可在項目中根據實際情況選擇應用,線程池的作用不僅僅是可控制創建線程的數量,更多的是在多線程中省去了頻繁的線程創建和銷毀過程,降低了系統銷毀。