線程池的學習

如下爲我的的學習和總結,若是隻是爲了瞭解線程池,能夠谷歌到大量優秀的文章.這裏只是爲了記錄個人學習思路,參考的其餘人的博客.,有些概括不正確之處望斧正 我會不斷概括總結新看到的文章來豐富細節java

爲何咱們要用線程池

除了用線程池代碼看起來比較高大上這個理由外,先說說用線程池和不用線程池相比都有什麼好處吧 我就用大白話解釋了,總比複製粘貼死記硬背好些吧......數組

  • 下降資源消耗 建立和銷燬線程是有成本消耗的.線程池正是爲了解決線程生命週期開銷問題和資源不足問題 經過重複利用已建立的線程下降線程建立和銷燬形成的消耗。 這就像一次性筷子和食堂用的消毒筷子同樣,不必每一個人吃完飯就把筷子銷燬從新作(雖然實際上這樣相對比較衛生......吧?)
  • 提升響應速度 當任務到達時,任務能夠不須要等到線程建立就能當即執行。 仍是拿筷子解釋吧(和食堂筷子卯上了),線程池就像裝筷子的消毒櫃,用時直接拿,用完再放回去.不必來我的吃飯(執行任務)就說:咱們在給你準備一雙新筷子(建立新線程),你先等一下......
  • 提升線程的可管理性 線程是稀缺資源,若是無限制的建立,不只會消耗系統資源,還會下降系統的穩定性,使用線程池能夠進行統一的分配,調優和監控。可是要作到合理的利用線程池,必須對其原理了如指掌。 消毒櫃裏統一發放用完後洗過(回收)的筷子(線程),而不是來我的就弄一雙筷子,到最後筷子扔的處處都是

線程池的參數

會用線程池不就得了?爲啥還要學那些亂七八糟的參數?賊複雜還很差背. 業務驅動技術,咱們在實際業務中可能須要到用到擁有不一樣特性的線程池.廢話很少說,先來DIY吧學習

  • corePoolSize(線程池的基本大小) 當提交一個任務到線程池時,線程池會建立一個線程來執行任務,即便其餘空閒的基本線程可以執行新任務也會建立線程,等到須要執行的任務數大於線程池基本大小時就再也不建立。若是調用了線程池的prestartAllCoreThreads方法,線程池會提早建立並啓動全部基本線程。 這裏講到了一個細節,核心線程能夠用到就建立,也能夠建立線程池時就直接建立好.這就比如行軍打仗以前或行軍中不斷籌備糧餉,線程池也會根據策略儘快湊足線程個數,以備不時之需
  • runnableTaskQueue(任務隊列) 用於保存等待執行的任務的阻塞隊列。 若是執行的任務過多,線程池放不下,就會放到任務隊列中. ArrayBlockingQueue:是一個基於數組結構的有界阻塞隊列,此隊列按 FIFO(先進先出)原則對元素進行排序。 LinkedBlockingQueue:一個基於鏈表結構的阻塞隊列,此隊列按FIFO (先進先出) 排序元素,吞吐量一般要高於ArrayBlockingQueue。靜態工廠方法Executors.newFixedThreadPool()使用了這個隊列。 SynchronousQueue:一個不存儲元素的阻塞隊列。每一個插入操做必須等到另外一個線程調用移除操做,不然插入操做一直處於阻塞狀態,吞吐量一般要高於LinkedBlockingQueue,靜態工廠方法Executors.newCachedThreadPool使用了這個隊列。 SynchronousQueue沒有容納元素的能力,即它的isEmpty()方法老是返回true,可是給人的感受卻像是隻能容納一個元素。它模擬的功能相似於生活中一手交錢一手交貨這種情形 PriorityBlockingQueue:一個具備優先級的無限阻塞隊列。
  • maximumPoolSize(線程池最大大小):線程池容許建立的最大線程數。若是隊列滿了,而且已建立的線程數小於最大線程數,則線程池會再建立新的線程執行任務。值得注意的是若是使用了無界的任務隊列這個參數就沒什麼效果。
  • ThreadFactory:用於設置建立線程的工廠,能夠經過線程工廠給每一個建立出來的線程設置更有意義的名字。
  • RejectedExecutionHandler(飽和策略):當隊列和線程池都滿了,說明線程池處於飽和狀態,那麼必須採起一種策略處理提交的新任務。這個策略默認狀況下是AbortPolicy,表示沒法處理新任務時拋出異常。如下是JDK1.5提供的四種策略。 AbortPolicy(捨棄-拋出異常):直接拋出異常。 CallerRunsPolicy(調用者執行):只用調用者所在線程來運行任務。 DiscardOldestPolicy(丟棄最舊的):丟棄隊列裏最近的一個任務,並執行當前任務。 DiscardPolicy(丟棄):不處理,丟棄掉。 固然也能夠根據應用場景須要來實現RejectedExecutionHandler接口自定義策略。如記錄日誌或持久化不能處理的任務。
  • keepAliveTime(線程活動保持時間):線程池的工做線程空閒後,保持存活的時間。因此若是任務不少,而且每一個任務執行的時間比較短,能夠調大這個時間,提升線程的利用率。
  • TimeUnit(線程活動保持時間的單位):可選的單位有天(DAYS),小時(HOURS),分鐘(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

參數比較多,但咱們要抓住重點去理解而不是死記硬背.線程池長啥樣?簡單描述就是個帶着個阻塞隊列的池子.固然它不是"死"的,它有本身解決特殊問題的各類的策略(飽和策略)線程

線程池的建立

new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, milliseconds,runnableTaskQueue, handler);rest

提交任務

有兩種方式提交: execute 和 submit日誌

  • execute方法沒有返回值,因此沒法判斷任務是否被線程池執行成功。
  • submit 方法會返回一個future,能夠經過這個future來判斷任務是否執行成功,經過future的get方法來獲取返回值,get方法會阻塞住直到任務完成,而使用get(long timeout, TimeUnit unit)方法則會阻塞一段時間後當即返回,這時有可能任務沒有執行完。

線程池的關閉

shutdown或shutdownNow方法來關閉線程池 原理是遍歷線程池中的工做線程,而後逐個調用線程的interrupt方法來中斷線程,因此沒法響應中斷的任務可能永遠沒法終止。 shutdownNow首先將線程池的狀態設置成STOP,而後嘗試中止全部的正在執行或暫停任務的線程,並返回等待執行任務的列表 shutdown只是將線程池的狀態設置成SHUTDOWN狀態,而後中斷全部沒有正在執行任務的線程。code

線程池工做流程

線程池工做流程

線程池的處理流程以下:排序

首先線程池判斷基本線程池是否已滿?沒滿,建立一個工做線程來執行任務。滿了,則進入下個流程。 其次線程池判斷工做隊列是否已滿?沒滿,則將新提交的任務存儲在工做隊列裏。滿了,則進入下個流程。 最後線程池判斷整個線程池是否已滿?沒滿,則建立一個新的工做線程來執行任務,滿了,則交給飽和策略來處理這個任務。接口

線程池的監控

經過線程池提供的參數進行監控。線程池裏有一些屬性在監控線程池的時候可使用 taskCount:線程池須要執行的任務數量。 completedTaskCount:線程池在運行過程當中已完成的任務數量。小於或等於taskCount。 largestPoolSize:線程池曾經建立過的最大線程數量。經過這個數據能夠知道線程池是否滿過。如等於線程池的最大大小,則表示線程池曾經滿了。 getPoolSize:線程池的線程數量。若是線程池不銷燬的話,池裏的線程不會自動銷燬,因此這個大小隻增不+ getActiveCount:獲取活動的線程數。生命週期

相關文章
相關標籤/搜索