為了更好的使用多執行緒,jdk提供了執行緒池供開發人員使用,目的在於減少執行緒的建立和銷毀次數,以此達到執行緒的重複利用。
其中threadpoolexecutor是執行緒池中最核心的乙個類,我們先簡單看一下這個類的繼承關係。
其中executor是執行緒池的頂級介面,介面中只定義了乙個方法 void execute(runnable command);執行緒池的操作方法都是定義子在executorservice子介面中的,所以說executorservice是執行緒池真正的介面。
threadpoolexecutor提供了四個構造方法,我們看一下引數最全的乙個建構函式;
public threadpoolexecutor(int corepoolsize,函式的引數含義如下:int maximumpoolsize,
long keepalivetime,
timeunit unit,
blockingqueueworkqueue,
threadfactory threadfactory,
rejectedexecutionhandler handler)
本節我們主要對前五個引數中的corepoolsize,maximumpoolsize及workqueue是如何配合使用做出說明(keepalivetime,unit主要對空閒執行緒的存活時間做的定義,見名知意,不再做出說明),以此來引出執行緒池的一些特性。
threadfactory和handler這兩個引數都有預設值,對於它們的用法將放到其它章節去做說明。
特性一:當池中正在執行的執行緒數(包括空閒執行緒)小於corepoolsize時,新建執行緒執行任務。
下面用實驗來說明,**如下:
public class testthreadpoolexecutor實驗結果如下:});try catch (interruptedexception e)
//任務2
pool.execute(new runnable()
});}
}
實驗結果分析:
從實驗結果上可以看出,當執行任務1的執行緒(thread-1)執行完成之後,任務2並沒有去復用thread-1而是新建執行緒(thread-2)去執行任務。
特性二:當池中正在執行的執行緒數大於等於corepoolsize時,新插入的任務進入workqueue排隊(如果workqueue長度允許),等待空閒執行緒來執行。
下面用實驗來說明,**如下:
public class testthreadpoolexecutor catch (interruptedexception e)實驗結果如下:}});
// 任務2
pool.execute(new runnable() catch (interruptedexception e)
}});
// 任務3
pool.execute(new runnable()
});}
}
實驗結果分析:
從實驗結果上看,任務3會等待任務1執行完之後,有了空閒執行緒,才會執行。並沒有新建執行緒執行任務3,這時maximumpoolsize=3這個引數不起作用。
特性三:當佇列裡的任務數達到上限,並且池中正在執行的執行緒數小於maximumpoolsize,
對於新加入的任務,新建執行緒。
下面用實驗來說明,**如下:
public class testthreadpoolexecutor catch (interruptedexception e)實驗結果如下:}});
// 任務2
pool.execute(new runnable() catch (interruptedexception e)
}});
// 任務3
pool.execute(new runnable()
});// 任務4
pool.execute(new runnable()
});}
}
實驗結果分析:
當任務4進入佇列時發現佇列的長度已經到了上限,所以無法進入佇列排隊,而此時正在執行的執行緒數(2)小於maximumpoolsize所以新建執行緒執行該任務。
特性四:當佇列裡的任務數達到上限,並且池中正在執行的執行緒數等於maximumpoolsize,
對於新加入的任務,執行拒絕策略(執行緒池預設的拒絕策略是拋異常)。
下面用實驗來說明,**如下:
public class testthreadpoolexecutor catch (interruptedexception e)實驗結果如下:}});
// 任務2
pool.execute(new runnable() catch (interruptedexception e)
}});
// 任務3
pool.execute(new runnable()
});// 任務4
pool.execute(new runnable() catch (interruptedexception e)
system.out.println("-------------helloworld_004---------------" + thread.currentthread().getname());
}});
// 任務5
pool.execute(new runnable()
});}
}
實驗結果分析:
當任務5加入時,佇列達到上限,池內執行的執行緒數達到最大,故執行預設的拒絕策略,拋異常。
本文中使用到的佇列型別雖然僅限於linkedblockingqueue這一種佇列型別,但總結出來的特性,對與常用arrayblockingqueue 和 synchronousqueue同樣適用,些許不同及三種佇列的區別,將在下個章節中說明。
最後說一點,我們作為程式設計師,研究問題還是要仔細深入一點的。當你對原理了解的有夠透徹,開發起來也就得心應手了,很多開發中的問題和疑惑也就迎刃而解了,而且在面對其他問題的時候也可做到觸類旁通。當然在開發中沒有太多的時間讓你去研究原理,開發中要以實現功能為前提,可等專案上線的後,你有大把的時間或者空餘的時間,你大可去刨根問底,深入的去研究一項技術,為覺得這對一名程式設計師的成長是很重要的事情。
ThreadPoolExecutor使用小結
記錄一下那幾個引數的理解,網上說了亂七八糟,詳細看參考文件,很詳細很明白,沒什麼好說的。corepoolsize,maximumpoolsize,keepalivetime keepalivetime workqueue queue blocksize 執行執行緒後,會判斷數量是否超出corepoo...
ThreadPoolExecutor簡單介紹
在專案中如果使用發簡訊這個功能,一般會把發簡訊這個動作變成非同步的,因為大部分情況下,簡訊到底是傳送成功或者失敗,都不能影響主流程。當然像傳送mq訊息等操作也是可以封裝成非同步操作的。如果想乙個操作變成非同步的,可以直接new thread,然後在run方法中實現業務操作即可。例如 new thre...
ThreadPoolExecutor執行緒池原始碼解讀
主要變數 private volatile int corepoolsize private volatile int maximumpoolsize private volatile int poolsize 建構函式 也就是建立類的時候,需要注入引數。public threadpoolexecu...