怎麼給女友講明白線程池?


前言前端

線程池是Java面試必問問題之一!面試

有沒有對源碼倒背如流的童鞋?請舉手!  ‍♂️(怎麼沒人舉手。。)ide


對了,今天先來撒一波狗狼~函數

dee920096620e63b3acc6f16d66cf8eb.png

(表打我~)工具

來,介紹下:學習


7000fecaeb27a39084c6ba12ce556946.jpeg


她叫碼妞,是我碼仔的女友喔!動畫

她也在學習各種前端技術,可厲害了!線程

你們鼓掌歡迎吧!之後她會常常來問我問題的,要被煩了~3d

最近碼妞也在看Java線程池呢,已經看得一頭霧水了,正準備去問問碼仔,blog

看碼仔能不能給她講明白了!



734340d9cd7b86dc86710bed293d4d67.jpegbde9a8e7a3e7506e99e7f631f575dea1.jpeg






134d0deaf3537862a053a62bb4bf0c8f.jpeg3d3645a2ce2d92636e9e0d23839ac294.jpeg









c9a7830d063861c88c5081048a183445.jpeg6333ee1906410d6d96e9a8851adcd165.jpeg



線程


線程是一種資源,並非只存在程序的世界裏。

程序,原本就是對生活的一種抽象表述。

好比像車站的售票窗口、退票窗口、檢票窗口,每一個窗口都在作不一樣的事情,就是車站裏同時運行着的不一樣線程。

線程多了,須要管理,不一樣的線程也要能保證不會互相干擾,各作各的。



a7d945a78185f1f0055e4e6ead3444f7.jpeg




bf72281851da4c63a42f3b660083e48b.jpeg



線程的生命週期

這個圖很熟悉的吧~


7c520e4114b9c2b00d3b838e76640553.jpeg



98782f13b21dd60e5f690f3931d81e2e.jpeg



好,開始講線程池啦~


ThreadPoolExecutor


線程池源碼裏最主要的類了~


看下開頭的這段註釋:

1eea1fea21a46a6fdeae195d2e011874.jpeg


看到英文就頭暈?沒事啦~


主要講線程池重要的兩個狀態:

  • runState:線程池運行狀態
  • workerCount:工做線程的數量

f7db8dd56b587cbb7b1b4153f082bb75.jpeg

線程池用一個32位的int來同時保存runState和workerCount,其中高3位(第31到29位)是runState,其他29位是workerCount(大約500 million)。

來看看存儲結構(碼仔手動畫的哦)

dc371a1defaa28e53f26aa22e6d4580c.jpeg

它的構造方法

c571233653242beed52b14e48bd8f97c.jpeg


629009101b65ce029d23bbdceb4e07c7.jpeg



01ae536ca3253f1f291427f53959d6bf.jpeg



  • corePoolSize

核心線程數,比如班幹部的人數。


  • maximumPoolSize

最大線程數,比如教室裏的座位數。 當提交任務數超過了這個最大值,線程還有拒絕策略——RejectExecutionHandler,作不動了嘛。


  • keepAliveTime

除核心線程外的空閒線程保持存活時間。 當線程池裏線程數超過corePoolSize數量了,keepAliveTime時間到,就把空閒線程關了,否則也閒置了呀,節省能量嘛。


  • workQueue
    任務阻塞隊列。經過workQueue,線程池實現了阻塞功能。 當線程池中的線程數超過它的corePoolSize的時候,線程會進入阻塞隊列進行阻塞等待。
  • threadFactory
    建立線程的工廠。全部的線程都是經過這個Factory建立的。
    默認會使用
    Executors.defaultThreadFactory() 來做線程工廠。

  • handler 線程池的飽和策略。作不了任務了找理由罷工

dee920096620e63b3acc6f16d66cf8eb.png


  • AbortPolicy
    • 直接拋出異常,默認策略;
  • CallerRunsPolicy
    • 用調用者所在的線程來執行任務;
  • DiscardOldestPolicy
    • 丟棄阻塞隊列中靠最前的任務,並執行當前任務;
  • DiscardPolicy
    • 直接丟棄任務。



9ad2cec7d011e29e89fc289e61c3004a.jpeg



d4317ff867a4911cd309447eae11146e.jpeg



Worker來了!



516c1cfa95d34167225f16cfea3d78b2.jpeg


你看Worker的定義,其實它就是封裝了的工做線程~

2728adcf4a4fa0e463b0410d439e3e52.png

Worker既實現了Runnable,又繼承了AbstractQueuedSynchronizer(AQS),因此它既是一個可執行的任務,又能夠達到鎖的效果。



5cab1127aa73410ab6e831cf5a9e59bb.jpeg1244d62a721708d0246982db63cf612d.jpeg






看看Worker構造方法:

44a6a585218e252dd192f1bb1e1f23bb.jpeg


946250b825aa871b4afbd2ae1a1dd4bc.jpegd99d6a6754388fa741a7077cd6f3668a.jpeg







f97f64e0fe731cebe6f5fbb2faf0cd7b.jpegc8ac705e8f722c0505a9a5eb7c5838a9.jpeg




線程池是怎麼工做的?


DuangDuangDuang!



4e8218e9623e3c86db6f70cc48ed10e6.jpeg



cdff4091c18328e54c190abcd3f7c27e.jpeg88a3e042f2b3e7ded9dfdb79ba9b6a0a.jpeg10acfe8eda8aca91de6ba6bd09f005fb.jpegd9241d29dbe7dec01396672d4c469bda.jpeg

看execute方法裏的註釋,一步步說得很清楚。


  1. 若是當前正在運行的線程數 < corePoolSize,嘗試用給到的command來啓動一個新線程做爲第一個任務。
    調用addWorker方法,檢查runState和workerCount,而且若是增長線程的話,能防止產生錯誤警報,若是不能增長線程,則返回false。
  2. 若是一個任務被成功地加到隊列裏,仍然須要雙重檢驗來確認是否須要新建一個線程。
    (由於可能在上一次檢查後,已經存在的線程已經died)或者進入這個方法後,線程池已經被關閉了。因此咱們須要再次檢查state,若是線程池中止了須要回滾入隊列,若是池中沒有線程了,新建一個線程。
  3. 若是不能把任務加入隊列(可能線程池已經關閉或者滿了),那麼須要新開一個線程(往maxPoolSize發展)。若是失敗的話,說明線程池shutdown了或者滿了,就要拒絕這個任務了。



53748a021ebe1af2ecfedad6b67f3f60.jpeg



3b7f3bf4e687cab23de86706709d8659.jpeg


給你流程圖!


73b419d23adf7bfe676c7bfca94d10d8.jpeg



e4c6f247f60701a22f71362ca66e44e3.jpeg



6ead366a152df6f65d1b015ed91850f8.jpeg




fa1fe95f67e5641b48b80ee471bed6f4.jpeg


15f28fd757fe1bf3829d121a862a9ee1.jpeg


8c8b688ecc1391eab9f94ec3f6320939.jpeg






a82ffcc4e62379099df506bde47a1dd6.jpeg



46c3e8e7087f744b6a3458c179a42862.jpeged4a10a6a6afacf5efaa0864b9915c2d.jpeg





工具類 Executors


線程池裏還有個重要的類:Executors~

Executors是一個Java中的工具類,它提供工廠方法來建立不一樣類型的線程池。

用它能夠很方便地建立出下面幾種線程池來~

0148be02281f2041ff6b6b5c623151df.jpeg66d908a0f310d60e1cc8c641d3995d99.png

或者經過ThreadPoolExecutor的構造函數自定義須要的線程池。



c5b91a5853b8a95561a8b614eff82b76.jpeg



02158b377ad97ed442358bfd5bfbeae7.jpeg

相關文章
相關標籤/搜索