身爲程序員咱們對線程是再熟悉不過了,多線程併發算是Java進階的知識,用好多線程不容易有太多的坑。建立線程也算是一個"重"操做。建立線程的語句是new Thread()
咋一看好像就是new了一個對象。java
沒錯是new了個對象,可是不單單是普通對象那樣在堆中分配了一塊內存,它還須要調用操做系統內核API,而後操做系統再爲線程分配一些資源。因此較普通對象,線程就比較「重了」。因此咱們要避免頻繁的建立和銷燬線程,還得控制一下線程的數量。線程池就是用來完成這一項使命的。程序員
因此多線程就離不開線程池,因此要掌握多線程編程,線程池的瞭解必不可少。 線程池的設計就是採用生產者-消費者模式,線程池裏面的線程是消費者,咱們塞給線程池的任務是生產者。能夠理解成線程池就是火車站售票廳,線程池裏面的線程就是火車站售票廳窗口員工,咱們去買票或者退票改簽就是給窗口員工任務也就是生產,而後窗口員工幫咱們辦理業務,也就是消費。 通常咱們是用ThreadPoolExecutor
來建立線程池,我找了裏面參數最多的構造器。 編程
按字面翻譯過來就是核心池大小,其實就是線程池保有的最小的線程數,這裏須要注意一下,初始化線程池的時候,除非調用prestartAllCoreThreads或者prestartCoreThread這兩個方法,這兩個方法分別是在無任務到來以前預建立全部核心線程或者建立一個線程。不然線程池初始化後沒任務進來前是沒有線程的。只有當任務來了纔會建立線程。多線程
因此這裏保有的核心數指的是,當線程池建立了這麼多的線程以後,會保留的不會被回收的線程數,超過corePoolSize的線程在必定時間以後就會被回收。併發
可是java1.6新增了一個allowCoreThreadTimeOut(boolean value)方法,當設爲true時候,全部的線程都會超時回收,包括核心線程。操作系統
最大線程數,也就是池裏面能有的最大的線程數量。也就是火車站售票廳窗口全部的窗口都有員工在服務。特別是在節假日的時候,基本上窗口都會開放。線程
keepAliveTime就是存活時間,TimeUnit是時間單位,來代表keepAliveTime的數字是秒啊仍是毫秒啊等等。 這兩個參數就是當咱們線程池存在的線程數量超過corePoolSize時,若是有個線程已經空閒了keepAliveTime這麼長的時間,那麼這個空閒線程就要被回收了,就相似於出行高峯期過去了,售票廳窗口能夠關閉幾個了。總不能都沒人了還開這麼多窗口把,浪費呀。翻譯
工做隊列,是阻塞隊列。隊列存儲的也就是線程須要執行的Runnable,也就是任務。對應着就是去售票廳排隊的咱們。設計
按名字翻譯過來就是線程工廠了,也就是咱們能夠搞個工廠,而後自定義如何建立線程,好比給線程set下名字啊等。而後線程池就會按照工廠定義的方式建立線程。就是若是不設定線程的名字的話,線程名可能就是什麼thread-1這樣的,對於咱們排查問題不太方便,因此給個名字來標識一下比較好。rest
這個是拒絕策略,也就是當線程池中全部的線程都在執行任務,而且工做隊列(是有界隊列)也排滿了,那再有任務提交就會執行拒絕策略。ThreadPoolExecutor提供了四種拒絕策略 一、ThreadPoolExecutor.AbortPolicy()
是默認的拒絕策略,會拋出 RejectedExcecutionException。 二、ThreadPoolExecutor.CallerRunsPolicy()
讓提交任務的線程本身去執行這個任務。。好像這樣作挺有道理的..我沒空你本身搞去 三、ThreadPoolExecutor.DiscardOldestPolicy()
丟棄最老的任務,也就是工做隊列裏最前面的任務,丟棄了以後把新任務加入到工做隊列中...真的不公平啊 四、ThreadPoolExecutor.DiscardPolicy()
直接丟棄任務,而且不拋出任何異常...僞裝沒看到系列
除了這四種還能夠自定義拒絕策略,建議自定義拒絕策略。由於更加的友好,能夠設置成服務降級啊等操做。
Java併發包還提供了Executors
,能夠快速建立線程池,可是不推薦使用Executors
。由於Executors建立線程池都是默認使用無界隊列LinkedBlockingQueue
,在高負載的狀況下容易OOM。因此建議使用有界隊列。
因此線程池就是生產者-消費者模型的實現,線程池約束了線程的數量,也避免頻繁的建立和銷燬線程。工做隊列得存在使得任務有序的進行,完美!
若有錯誤歡迎指正! 我的公衆號:yes的練級攻略