程序運行,其本質上,是對系統資源(CPU、內存、磁盤、網絡等等)的使用。如何高效的使用這些資源是咱們編程優化演進的一個方向。今天說的線程池是對CPU的利用的優化手段。java
網上有很多介紹如何使用線程池的文章,那我想說點什麼呢?我但願查看線程池原理,明白池化技術的基本設計思路。遇到其餘類似問題能夠解決。編程
何爲池化技術,簡單點來講,就是提早保存大量的資源,以備不時之需。在資源有限的狀況下,該技術能夠大大提高資源的利用率,提高性能等。微信
目前比較典型的池化技術有: 線程池、鏈接池、內存池、對象池等。網絡
本文主要來介紹一下其中比較簡單的線程池的實現原理,但願讀者們能夠觸類旁通,經過對線程池的理解,學習並掌握全部的編程中池化技術的底層原理,一通百通。併發
在java的併發編程中,線程是十分重要的,在Java中,建立一個線程比較簡單:ide
public class App {
public static void main(String[] args) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("線程運行中");
}
}).start();
}
}
複製代碼
咱們經過建立一個線程對象,而且實現Runnable接口就能夠實現一個簡單的線程。能夠利用上多核CPU。當一個任務結束,當前線程就結束。函數
但不少時候,咱們不止會執行一個任務。若是每次都是如此的建立線程->執行任務->銷燬線程,會形成很大的性能開銷的。工具
那可否一個線程建立後,執行完一個任務後,又去執行另外一個任務,而不是銷燬。這就是線程池。性能
這就是池化技術的思想,經過預先建立好多個線程,放在池中,這樣能夠在須要使用線程的時候直接獲取,避免屢次重複建立、銷燬代理的開銷。學習
如下代碼,就是在java中建立線程池:
import java.util.concurrent.*;
public class App {
public static void main(String[] args) throws Exception {
ExecutorService executorService = new ThreadPoolExecutor(1, 1,
60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(10));
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println("abcdefg");
}
});
executorService.shutdown();
}
}
複製代碼
JDK提供給外部的接口也很簡單。直接調用ThreadPoolExecutor構造一個就能夠了,也能夠經過Executors靜態工廠構建,但通常不建議。
能夠看到,開發者想要在代碼中使用線程池仍是比較簡單的,這得益於Java給咱們封裝好了一系列的API。不少時候,咱們須要知道這些API後面幹了些啥,以便於咱們更好的設計與實現咱們的代碼。
一般,通常構造函數會反映出這個工具或這個對象的數據存儲結構。
若是把線程池比做一個公司。公司會有正式員工處理正常業務,若是工做量大的話,會僱傭外包人員來工做。閒時就能夠釋放外包人員以減小公司管理開銷。一個公司由於成本關係,僱傭的人員始終是有最大數。若是這時候還有任務處理不過來,就走需求池排任務。
這裏邏輯稍微有點複雜,畫了個流程圖僅供參考
接下來,咱們看看如何添加一個工做線程的? addWork
有人或許會疑問 retry 是什麼?這個是java中的goto語法。只能運用在break和continue後面。
接下來,咱們看看works是什麼。
這兩個鉤子(beforeExecute,afterExecute)容許咱們本身繼承線程池,作任務執行先後處理。有意思。 到這裏,源代碼分析到此爲止。接下來作一下簡單的總結。
最後但願對你理解線程池有幫助。
都看到這裏了,成神之路上,要不要一塊兒?