1.執行緒池執行流程
2.執行緒池的執行緒是如何做到復用的
執行緒池中的執行緒在迴圈中嘗試取任務執行,這一步會被阻塞,如果設定了allowcorethreadtimeout為true,則執行緒池中的所有執行緒都會在keepalivetime時間超時後還未取到任務而退出。或者執行緒池已經stop,那麼所有執行緒都會被中斷,然後退出。
3.執行緒狀態和工作執行緒數量
3.1執行緒池狀態
執行狀態(running):此狀態下,執行緒池可以接受新的任務,也可以處理阻塞佇列中的任務。執行shutdown()方法可進入待關閉(shutdown)狀態,執行shutdownnow()方法可進入停止(stop)狀態。
停止狀態(stop):此狀態下,執行緒池不接受新任務,也不處理阻塞佇列中的任務,反而會嘗試結束執行中的任務。當工作執行緒數為0時,進入整理(tidying)狀態。
待關閉狀態(shutdown):此狀態下,執行緒池不再接受新的任務,繼續處理阻塞佇列中的任務。當阻塞佇列中的任務為空,且工作執行緒數為0的時候,進入整理(tidying)狀態。
整理狀態(tidying):此狀態下,所有任務都已經執行完畢,且沒有工作執行緒。執行terminated()方法進入終止(terminated)狀態。
終止狀態(terminated):此狀態下,執行緒池完全終止,並完成了所有資源的釋放。
4.核心執行緒數和最大執行緒數和工作執行緒個數的關係是什麼呢?
工作執行緒的個數可能從0到最大執行緒數之間變化,當執行一段時間之後可能維持在核心執行緒數(corepoolsize),但也不是絕對的,取決於核心執行緒是否允許被超時**。
5.核心執行緒/非核心執行緒存活時間
5.1存活時間
上面我們說了,當工作執行緒數達到corepoolsize時,執行緒池會將新接收到的任務放在阻塞佇列中,而阻塞佇列又分為兩種情況:一種是有界的佇列,一種是無界的佇列。
如果是無界佇列,那麼當核心執行緒都在忙時,所有新提交的任務都會被存放在該無界佇列中,這時最大執行緒數將變得沒有意義,因為阻塞佇列不會存在被裝滿的情況。
如果是有界佇列,那麼當阻塞佇列中裝滿了等待執行的任務,這時再有新任務提交時,執行緒池就需要建立新的臨時執行緒來處理,相當於增派人手來處理任務。
但是建立的臨時執行緒是有存活時間的,不可能讓它們一直都存活著,當阻塞佇列中的任務被執行完畢,並且又沒有那麼多新任務被提交時,臨時執行緒就需要被**銷毀,而在被**銷毀之前等待的這段時間,就是非核心執行緒的存活時間,也就是keepalivetime屬性。
5.2什麼是非核心執行緒呢?是不是先建立的執行緒就是核心執行緒,後建立的就是非核心執行緒呢?
其實核心執行緒跟建立的先後沒有關係,而是跟工作執行緒的個數有關,如果當前工作執行緒的個數大於核心執行緒數,那麼所有的執行緒都可能是非核心執行緒,都有被**的可能。
5.3怎麼保證核心執行緒不會被**呢?還是跟工作執行緒的個數有關,每乙個執行緒在取任務的時候,執行緒池會比較當前的工作執行緒個數與核心執行緒數。
乙個執行緒執行完乙個任務後,會去阻塞佇列裡面取新的任務,在取到任務之前,它就是乙個閒置的執行緒。
取任務的方法有兩種,一種是通過take()方法一直阻塞直到取出任務,另一種是通過poll(keepalivetime, timeunit)方法在一定時間內取出任務或者超時,如果超時這個執行緒就會被**,請注意核心執行緒一般不會被**。
1.如果工作執行緒數小於當前的核心執行緒數,則使用第一種方法取任務,也就是沒有超時**,這時所有的工作執行緒都是核心執行緒,它們不會被**。
2.如果工作執行緒數大於核心執行緒數,則使用第二種方法取任務,一旦超時就**,所以並沒有絕對的核心執行緒,只要這個執行緒沒有在存活時間內取到任務去執行就會被**。
核心執行緒一般不會被**,但是也不是絕對的,如果我們設定了允許核心執行緒超時被**的話,那麼就沒有核心執行緒這種說法了,所有的執行緒都會通過poll(keepalivetime, timeunit)來獲取任務,一旦超時獲取不到任務,就會被**,一般很少會這樣來使用,除非該執行緒池需要處理的任務非常少,並且頻率也不高,不需要將核心執行緒一直維持著。
6.常見執行緒池
①newsinglethreadexecutor
建立乙個單執行緒的執行緒池。這個執行緒池只有乙個執行緒在工作,也就是相當於單執行緒序列執行所有任務。
如果這個唯一的執行緒因為異常結束,那麼會有乙個新的執行緒來替代它。此執行緒池保證所有任務的執行順序按照任務的提交順序執行。
②newfixedthreadexecutor(n)
固定數量的執行緒池,每提交乙個任務就是乙個執行緒,直到達到執行緒池的最大數量,然後後面進入等待佇列直到前面的任務完成才繼續執行
建立固定大小的執行緒池。每次提交乙個任務就建立乙個執行緒,直到執行緒達到執行緒池的最大大小。執行緒池的大小一旦達到最大值就會保持不變,如果某個執行緒因為執行異常而結束,那麼執行緒池會補充乙個新執行緒。
③newcachethreadexecutor(推薦使用)
可快取執行緒池,當執行緒池大小超過了處理任務所需的執行緒,那麼就會**部分空閒(一般是60秒無執行)的執行緒,當有任務來時,又智慧型的新增新執行緒來執行。
此執行緒池不會對執行緒池大小做限制,執行緒池大小完全依賴於作業系統(或者說jvm)能夠建立的最大執行緒大小。
④newschedulethreadexecutor
大小無限制的執行緒池,支援定時和週期性的執行執行緒
7.執行緒池拒絕策略
abortpolicy策略:該策略會直接丟擲異常,阻止系統正常工作。
callerrunspolicy 策略:只要執行緒池未關閉,該策略直接在呼叫者執行緒中,執行當前的被丟棄的任務。
discardoleddestpolicy策略: 該策略將丟棄最老的乙個請求,也就是即將被執行的任務,並嘗試再次提交當前任務。
discardpolicy策略:該策略默默的丟棄無法處理的任務,不予任何處理。
java 面試題 記憶體池 程序池 執行緒池
自定義記憶體池的思想通過這個 池 字表露無疑,應用程式可以通過系統的記憶體分配呼叫預先一次性申請適當大小的記憶體作為乙個記憶體池,之後應用程式自己對記憶體的分配和釋放則可以通過這個記憶體池來完成。只有當記憶體池大小需要動態擴充套件時,才需要再呼叫系統的記憶體分配函式,其他時間對記憶體的一切操作都在應...
面試題 執行緒
今天公司新來的小夥伴問了我這樣乙個面試題 他不清楚為什麼最後輸出的是thread中的方法,而不是runnable中的方法,然後我看了下他從網上搜出的別人寫的答案,很多東西對於懂的人來說很容易就能看懂,但是對於剛剛踏入這一行業的人來說,他不明白。所以希望很多在這塊迷茫的小夥伴能夠更好的掌握這一點,那麼...
多執行緒面試題 一
1 多執行緒有幾種實現方案,分別是哪幾種?兩種。繼承thread類 實現runnable介面 擴充套件一種 實現callable介面。這個得和執行緒池結合。2 同步有幾種方式,分別是什麼?兩種。同步 塊 同步方法3 啟動乙個執行緒是run 還是start 它們的區別?start run 封裝了被執行...