关于线程池ThreadPoolExecutor使用总结
本文引用自:
http://blog.chinaunix.net/uid-20577907-id-3519578.html?
?
一、簡介?
線程池類為 java.util.concurrent.ThreadPoolExecutor,常用構造方法為:?
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,?long keepAliveTime, TimeUnit unit,?BlockingQueue?workQueue,?RejectedExecutionHandler handler)?
corePoolSize: 線程池維護線程的最少數量?
maximumPoolSize:線程池維護線程的最大數量?
keepAliveTime: 線程池維護線程所允許的空閑時間?
unit: 線程池維護線程所允許的空閑時間的單位?
workQueue: 線程池所使用的緩沖隊列?
handler: 線程池對拒絕任務的處理策略?
一個任務通過 execute(Runnable)方法被添加到線程池,任務就是一個 Runnable類型的對象,任務的執(zhí)行方法就是 Runnable類型對象的run()方法。?
當一個任務通過execute(Runnable)方法欲添加到線程池時:?
如果此時線程池中的數量小于corePoolSize,即使線程池中的線程都處于空閑狀態(tài),也要創(chuàng)建新的線程來處理被添加的任務。?
如果此時線程池中的數量等于 corePoolSize,但是緩沖隊列 workQueue未滿,那么任務被放入緩沖隊列。?
如果此時線程池中的數量大于corePoolSize,緩沖隊列workQueue滿,并且線程池中的數量小于maximumPoolSize,建新的線程來處理被添加的任務。?
如果此時線程池中的數量大于corePoolSize,緩沖隊列workQueue滿,并且線程池中的數量等于maximumPoolSize,那么通過 handler所指定的策略來處理此任務。?
?
也就是:處理任務的優(yōu)先級為:?
核心線程corePoolSize、任務隊列workQueue、最大線程maximumPoolSize,如果三者都滿了,使用handler處理被拒絕的任務。?
當線程池中的線程數量大于 corePoolSize時,如果某線程空閑時間超過keepAliveTime,線程將被終止。這樣,線程池可以動態(tài)的調整池中的線程數。?
unit可選的參數為java.util.concurrent.TimeUnit中的幾個靜態(tài)屬性:?NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。?
workQueue我常用的是:java.util.concurrent.ArrayBlockingQueue?
handler有四個選擇:?
ThreadPoolExecutor.AbortPolicy()?
拋出java.util.concurrent.RejectedExecutionException異常?
ThreadPoolExecutor.CallerRunsPolicy()?
重試添加當前的任務,他會自動重復調用execute()方法?
ThreadPoolExecutor.DiscardOldestPolicy()?
拋棄舊的任務?
ThreadPoolExecutor.DiscardPolicy()?
拋棄當前的任務?
?
二、一般用法舉例?
1 import java.io.Serializable; 2 import java.util.concurrent.ArrayBlockingQueue; 3 import java.util.concurrent.ThreadPoolExecutor; 4 import java.util.concurrent.TimeUnit; 5 6 public class TestThreadPool { 7 8 private static int produceTaskSleepTime = 2; 9 10 private static int produceTaskMaxNumber = 10; 11 12 public static void main(String[] args) { 13 // 構造一個線程池 14 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3), 15 new ThreadPoolExecutor.DiscardOldestPolicy()); 16 // corePoolSize: 線程池維護線程的最少數量 ==============>2 17 // maximumPoolSize:線程池維護線程的最大數量 ==============>4 18 // keepAliveTime: 線程池維護線程所允許的空閑時間 ==============>3 19 // unit: 線程池維護線程所允許的空閑時間的單位 ==============>TimeUnit.SECONDS 20 // workQueue: 線程池所使用的緩沖隊列 ==============>new ArrayBlockingQueue<Runnable>(3) 21 // handler: 線程池對拒絕任務的處理策略 ==============>new ThreadPoolExecutor.DiscardOldestPolicy() 22 23 for (int i = 1; i <= produceTaskMaxNumber; i++) { 24 try { 25 // 產生一個任務,并將其加入到線程池 26 String task = "task@ " + i; 27 System.out.println("put " + task); 28 threadPool.execute(new ThreadPoolTask(task)); 29 30 // 便于觀察,等待一段時間 31 Thread.sleep(produceTaskSleepTime); 32 } catch (Exception e) { 33 e.printStackTrace(); 34 } 35 } 36 } 37 } 38 39 /** 40 * 線程池執(zhí)行的任務 41 */ 42 class ThreadPoolTask implements Runnable, Serializable { 43 44 private static final long serialVersionUID = 0; 45 46 private static int consumeTaskSleepTime = 2000; 47 48 // 保存任務所需要的數據 49 private Object threadPoolTaskData; 50 51 ThreadPoolTask(Object tasks) { 52 this.threadPoolTaskData = tasks; 53 } 54 55 public void run() { 56 // 處理一個任務,這里的處理方式太簡單了,僅僅是一個打印語句 57 System.out.println(Thread.currentThread().getName()); 58 System.out.println("start .." + threadPoolTaskData); 59 60 try { 61 //便于觀察,等待一段時間 62 Thread.sleep(consumeTaskSleepTime); 63 } catch (Exception e) { 64 e.printStackTrace(); 65 } 66 threadPoolTaskData = null; 67 } 68 69 public Object getTask() { 70 return this.threadPoolTaskData; 71 } 72 }?
說明:?
1、在這段程序中,一個任務就是一個Runnable類型的對象,也就是一個ThreadPoolTask類型的對象。?
2、一般來說任務除了處理方式外,還需要處理的數據,處理的數據通過構造方法傳給任務。?
3、在這段程序中,main()方法相當于一個殘忍的領導,他派發(fā)出許多任務,丟給一個叫 threadPool的任勞任怨的小組來做。?
這個小組里面隊員至少有兩個,如果他們兩個忙不過來,任務就被放到任務列表里面。?
如果積壓的任務過多,多到任務列表都裝不下(超過3個)的時候,就雇傭新的隊員來幫忙。但是基于成本的考慮,不能雇傭太多的隊員,至多只能雇傭 4個。?
如果四個隊員都在忙時,再有新的任務,這個小組就處理不了了,任務就會被通過一種策略來處理,我們的處理方式是不停的派發(fā),直到接受這個任務為止(更殘忍!呵呵)。?
因為隊員工作是需要成本的,如果工作很閑,閑到 3SECONDS都沒有新的任務了,那么有的隊員就會被解雇了,但是,為了小組的正常運轉,即使工作再閑,小組的隊員也不能少于兩個。?
4、通過調整 produceTaskSleepTime和 consumeTaskSleepTime的大小來實現對派發(fā)任務和處理任務的速度的控制,改變這兩個值就可以觀察不同速率下程序的工作情況。?
5、通過調整4中所指的數據,再加上調整任務丟棄策略,換上其他三種策略,就可以看出不同策略下的不同處理方式。?
6、對于其他的使用方法,參看jdk的幫助,很容易理解和使用。?
?
另一個例子:?
1 import java.util.Queue; 2 import java.util.concurrent.ArrayBlockingQueue; 3 import java.util.concurrent.ThreadPoolExecutor; 4 import java.util.concurrent.TimeUnit; 5 6 public class ThreadPoolExecutorTest { 7 8 private static int queueDeep = 4; 9 10 public void createThreadPool() { 11 /* 12 * 創(chuàng)建線程池,最小線程數為2,最大線程數為4,線程池維護線程的空閑時間為3秒, 使用隊列深度為4的有界隊列,如果執(zhí)行程序尚未關閉,則位于工作隊列頭部的任務將被刪除, 13 * 然后重試執(zhí)行程序(如果再次失敗,則重復此過程),里面已經根據隊列深度對任務加載進行了控制。 14 */ 15 ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 4, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(queueDeep), 16 new ThreadPoolExecutor.DiscardOldestPolicy()); 17 18 // 向線程池中添加 10 個任務 19 for (int i = 0; i < 10; i++) { 20 try { 21 Thread.sleep(1); 22 } catch (InterruptedException e) { 23 e.printStackTrace(); 24 } 25 while (getQueueSize(tpe.getQueue()) >= queueDeep) { 26 System.out.println("隊列已滿,等3秒再添加任務"); 27 try { 28 Thread.sleep(3000); 29 } catch (InterruptedException e) { 30 e.printStackTrace(); 31 } 32 } 33 TaskThreadPool ttp = new TaskThreadPool(i); 34 System.out.println("put i:" + i); 35 tpe.execute(ttp); 36 } 37 38 tpe.shutdown(); 39 } 40 41 private synchronized int getQueueSize(Queue queue) { 42 return queue.size(); 43 } 44 45 public static void main(String[] args) { 46 ThreadPoolExecutorTest test = new ThreadPoolExecutorTest(); 47 test.createThreadPool(); 48 } 49 50 class TaskThreadPool implements Runnable { 51 52 private int index; 53 54 public TaskThreadPool(int index) { 55 this.index = index; 56 } 57 58 public void run() { 59 System.out.println(Thread.currentThread() + " index:" + index); 60 try { 61 Thread.sleep(3000); 62 } catch (InterruptedException e) { 63 e.printStackTrace(); 64 } 65 } 66 } 67 }?
轉載于:https://www.cnblogs.com/DreamDrive/p/4758260.html
總結
以上是生活随笔為你收集整理的关于线程池ThreadPoolExecutor使用总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我该如何维护一个烂项目?
- 下一篇: 添加删除 板块 struts2