Java線程池
我們平時在寫程式中常常使用多線程來提高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() + "正在執行。。。"); } }1.newCachedThreadPool
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(); } }運行效果:
2.newFixedThreadPool
建立一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。新的線程加入後,如果正在啟動並執行線程達到了上限,則會阻塞,直到有了閒置線程來運行。他是定長尺寸的線程池。
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(); } } 此時線程池的最大線程為3,運行效果:
3.newScheduledThreadPool
建立一個定長線程池,支援定時及週期性任務執行。順延強制範例程式碼如下:
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(); } } 運行效果(延遲過程需要自己實踐):
4.newSingleThreadExecutor
建立一個單線程化的線程池,它只會用唯一的背景工作執行緒來執行任務,保證所有任務按照指定順序(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(); } }
運行效果:
以上四中線程池分別運用於不同情境,可在項目中根據實際情況選擇應用,線程池的作用不僅僅是可控制建立線程的數量,更多的是在多線程中省去了頻繁的線程建立和銷毀過程,降低了系統銷毀。