1. 程式人生 > >來,我們在重新說下,執行緒狀態?

來,我們在重新說下,執行緒狀態?

>愛生活,愛編碼,微信搜一搜【**架構技術專欄**】關注這個喜歡分享的地方。 本文 [架構技術專欄](http://47.104.79.116:4321/) 已收錄,有各種圖文資料以及技術文章。 ## 苦惱 每當線上應用出現各種吞吐下降、RT增長、CPU飈高、記憶體溢位等問題的時候是不是腦闊疼。面對出現的問題,簡直就是無從下口啊。 不要慌,其實對於線上出現的各種奇葩問題,我們使用ThreadDump就能解決90%了。 很多時候根本不需要對JVM引數進行各種複雜的調優,好好看看執行緒棧,優化優化你的程式碼,簡直就是美滋滋的提升效能。 好了,言歸正傳,下面我們就來說下執行緒棧重點關注的點來協助我們進行問題的排查。 ## 執行緒狀態的種類 以前大家接觸到的執行緒狀態是:**BLOCKED**、**WAITING**、**TIMED_WAITING**、**RUNABLE**,今天我們換個說法來看,到底什麼樣的執行緒會出現這種狀態。 為了減少篇幅,執行緒棧的基本概念就不在這裡重複了,有興趣的可以看以前的文章 [ThreadDump分析實戰](https://mp.weixin.qq.com/s?__biz=MzI0MjE4NTM5Mg==&mid=2648975262&idx=1&sn=62213013b6b45cb927e34ce22ef27bc2&chksm=f110a241c6672b57a61a1e08f80c9ae6ec0c31c22331bea5815834de6aba5c64efe840696288&mpshare=1&scene=1&srcid=0918xasAvUFQqeAmLrZod2MU&sharer_sharetime=1600439782854&sharer_shareid=21ecfec3e297e501bd622ba10156dba9#rd) 。 **1、執行緒狀態為“waiting for monitor entry”:** 含義: 意味著它 **在等待進入一個臨界區** ,所以它在”Entry Set“佇列中等待。 此時狀態: **BLOCKED** 舉例: java.lang.Thread.State: **BLOCKED** (on object monitor) 知識點:注意 "Entry Set" 就是咱們平時經常使用synchronized 的時候執行緒所等待的區域 **2,如果大量執行緒在 “waiting for monitor entry”:** 含義:可能是一個全域性鎖阻塞住了大量執行緒,如果短時間內多次列印的 thread dump 檔案反映,隨著時間流逝,waiting for monitor entry 的執行緒越來越多,沒有減少的趨勢,可能意味著**某些執行緒在臨界區裡呆的時間太長了,以至於越來越多新執行緒遲遲無法進入臨界區**。 此時狀態:**BLOCKED** **3、執行緒狀態為“waiting on condition”:** 含義: 它**在等待另一個條件的發生,來把自己喚醒**,或者是它是呼叫了 sleep(N)。 此時狀態:**WAITING** || **TIMED_WAITING** 舉例: java.lang.Thread.State: **WAITING** (parking):一直等某個條件發生 java.lang.Thread.State: **TIMED_WAITING** (parking或sleeping):設有超時時間,那個條件不到來,也將定時喚醒自己。 **4,如果大量執行緒在“waiting on condition”:** 含義: 可能是它們又跑去獲取第三方資源,**尤其是第三方網路資源,遲遲獲取不到Response**,導致大量執行緒進入等待狀態。 所以如果你發現有大量的執行緒都處在 Wait on condition,從執行緒堆疊看,正等待網路讀寫**,這可能是一個網路瓶頸的徵兆**,因為網路阻塞導致執行緒無法執行。 此時狀態:**WAITING** || **TIMED_WAITING** **5、執行緒狀態為“in Object.wait()”:** 含義:說明它**獲得了監視器之後(也就是開始執行synchronized的方法),又呼叫了** **java.lang.Object.wait() 方法**。 每個 Monitor在某個時刻,只能被一個執行緒擁有,該執行緒就是 “Active Thread”,而其它執行緒都是 “Waiting Thread”,分別在兩個佇列 “ Entry Set”和 “Wait Set”裡面等候。在 “Entry Set”中等待的執行緒狀態是 “Waiting for monitor entry”,而在 “Wait Set”中等待的執行緒狀態是 “in Object.wait()”。 當執行緒獲得了 Monitor,如果發現執行緒繼續執行的條件沒有滿足,它則呼叫物件(一般就是被 synchronized 的物件)的 wait() 方法,放棄了 Monitor,進入 “Wait Set”佇列。 此時狀態:**TIMED_WAITING** || **WAITING** 舉例: - java.lang.Thread.State: **TIMED_WAITING** (on object monitor); - java.lang.Thread.State: **WAITING** (on object monitor); 知識點:一般都是RMI相關執行緒(RMI RenewClean、 GC Daemon、RMI Reaper),GC執行緒(Finalizer),引用物件垃圾回收執行緒(Reference Handler)等系統執行緒處於這種狀態,如圖。 ![](https://imgkr2.cn-bj.ufileos.com/06b79492-2b30-497e-84bd-2f1ae0fad33d.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=lV2QR0q8j%252F4G6YcmsHnwiT9XLSc%253D&Expires=1600528920) ## 上例子 光說肯定是乾巴巴的,下面我們來看幾個小樣,幫助大家消化消化。 #### Round 1 ``` 狀態:waiting for monitor entry BLOCKED 原因:這個執行緒在等待這個鎖 0x00000000fe7exx61,等待進入臨界區: "RMI TCP Connection(12345)-xxx.52.xxx" daemon prio=10 tid=0x00000000405a6000 nid=0x68fe waiting for monitor entry [0x00007f2be65a3000] java.lang.Thread.State: BLOCKED (on object monitor) at com.xyz.goods.service.impl.GoodsServiceImpl.findChanellGoodsCountWithCache(GoodsServiceImpl.java:1734) - waiting to lock <0x00000000fe7exx61> (a java.lang.String) 那麼當前誰持有這個鎖呢? 線上程棧中搜索0x00000000fe7exx61,我們會發現另一個執行緒呼叫了 - locked <0x00000000fe7exx61> 對現場進行了加鎖 "RMI TCP Connection(64878)-172.16.52.117" daemon prio=10 tid=0x0000000040822000 nid=0x6841 runnable [0x00007f2be76b3000] java.lang.Thread.State: RUNNABLE at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(SocketInputStream.java:129) at java.io.BufferedInputStream.fill(BufferedInputStream.java:218) at java.io.BufferedInputStream.read1(BufferedInputStream.java:258) at java.io.BufferedInputStream.read(BufferedInputStream.java:317) - locked <0x00000000af4ed638> (a java.io.BufferedInputStream) at org.bson.io.Bits.readFully(Bits.java:35) at org.bson.io.Bits.readFully(Bits.java:28) at com.mongodb.R