Java中常用的四種線程池


在Java中使用線程池,可以用ThreadPoolExecutor的構造函數直接創建出線程池實例,如何使用參見之前的文章Java線程池構造參數詳解。不過,在Executors類中,為我們提供了常用線程池的創建方法。接下來我們就來了解常用的四種:

newFixedThreadPool

首先,看一下這種線程池的創建方法:

public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }

從構造方法可以看出,它創建了一個固定大小的線程池,每次提交一個任務就創建一個線程,直到線程達到線程池的最大值nThreads。線程池的大小一旦達到最大值后,再有新的任務提交時則放入無界阻塞隊列中,等到有線程空閑時,再從隊列中取出任務繼續執行。
那么,如何使用newFixedThreadPool呢?我們來舉個例子:

public class OneMoreStudy { public static void main(String[] args) { ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); for (int i = 0; i < 5; i++) { final int index = i; fixedThreadPool.execute(new Runnable() { @Override public void run() { try { SimpleDateFormat sdf = new SimpleDateFormat( "HH:mm:ss"); System.out.println("運行時間: " + sdf.format(new Date()) + " " + index); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } fixedThreadPool.shutdown(); } }

上面的例子中創建了一個固定大小為3的線程池,然后在線程池提交了5個任務。在提交第4個任務時,因為線程池的大小已經達到了3並且前3個任務在運行中,所以第4個任務被放入了隊列,等待有空閑的線程時再被運行。運行結果如下(注意前3個任務和后2個任務的運行時間):

運行時間: 08:09:02 1 運行時間: 08:09:02 2 運行時間: 08:09:02 0 運行時間: 08:09:04 4 運行時間: 08:09:04 3

newCachedThreadPool

首先,看一下這種線程池的創建方法:

public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }

從構造方法可以看出,它創建了一個可緩存的線程池。當有新的任務提交時,有空閑線程則直接處理任務,沒有空閑線程則創建新的線程處理任務,隊列中不儲存任務。線程池不對線程池大小做限制,線程池大小完全依賴於操作系統(或者說JVM)能夠創建的最大線程大小。如果線程空閑時間超過了60秒就會被回收。
那么,如何使用newCachedThreadPool呢?我們來舉個例子:

public class OneMoreStudy { public static void main(String[] args) { ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) { final int index = i; cachedThreadPool.execute(new Runnable() { @Override public void run() { try { SimpleDateFormat sdf = new SimpleDateFormat( "HH:mm:ss"); System.out.println("運行時間: " + sdf.format(new Date()) + " " + index); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } cachedThreadPool.shutdown(); } }

因為這種線程有新的任務提交,就會創建新的線程(線程池中沒有空閑線程時),不需要等待,所以提交的5個任務的運行時間是一樣的,運行結果如下:

運行時間: 08:45:18 2 運行時間: 08:45:18 1 運行時間: 08:45:18 3 運行時間: 08:45:18 4 運行時間: 08:45:18 0

newSingleThreadExecutor

首先,看一下這種線程池的創建方法:

public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }

從構造方法可以看出,它創建了一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序執行。
那么,如何使用newSingleThreadExecutor呢?我們來舉個例子:

public class OneMoreStudy { public static void main(String[] args) { ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 5; i++) { final int index = i; singleThreadExecutor.execute(new Runnable() { @Override public void run() { try { SimpleDateFormat sdf = new SimpleDateFormat( "HH:mm:ss"); System.out.println("運行時間: " + sdf.format(new Date()) + " " + index); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } singleThreadExecutor.shutdown(); } }

因為該線程池類似於單線程執行,所以先執行完前一個任務后,再順序執行下一個任務,
運行結果如下:

運行時間: 08:54:17 0 運行時間: 08:54:19 1 運行時間: 08:54:21 2 運行時間: 08:54:23 3 運行時間: 08:54:25 4

有的同學可能會質疑:既然類似於單線程執行,那么這種線程池還有存在的必要嗎?這里的單線程執行指的是線程池內部,從線程池外的角度看,主線程在提交任務到線程池時並沒有阻塞,仍然是異步的。

newScheduledThreadPool

這個方法創建了一個固定大小的線程池,支持定時及周期性任務執行。
首先看一下定時執行的例子:

public class OneMoreStudy { public static void main(String[] args) { final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3); System.out.println("提交時間: " + sdf.format(new Date())); scheduledThreadPool.schedule(new Runnable() { @Override public void run() { System.out.println("運行時間: " + sdf.format(new Date())); } }, 3, TimeUnit.SECONDS); scheduledThreadPool.shutdown(); } }

使用該線程池的schedule方法,延遲3秒鍾后執行任務,運行結果如下:

提交時間: 09:11:39 運行時間: 09:11:42

再看一下周期執行的例子:

public class OneMoreStudy { public static void main(String[] args) { final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3); System.out.println("提交時間: " + sdf.format(new Date())); scheduledThreadPool.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("運行時間: " + sdf.format(new Date())); } }, 1, 3, TimeUnit.SECONDS); Thread.sleep(10000); scheduledThreadPool.shutdown(); } }

使用該線程池的scheduleAtFixedRate方法,延遲1秒鍾后每隔3秒執行一次任務,運行結果如下:

提交時間: 09:23:20 運行時間: 09:23:21 運行時間: 09:23:24 運行時間: 09:23:27


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM