本文來自: PerfMa技術社群
概述
老早之前寫過一篇文章,關於attach機制的,可以看下這篇老文章瞭解一下JVM原始碼分析之Attach機制實現完全解讀,比如大家常用的jstack,jmap等工具的主要原理都和attach機制有關,在JVM裡處理這些命令的執行緒主要是Attach Listener
這個執行緒,這個執行緒在JVM裡是唯一的,我之前也一直以為是唯一的,但是我們同事最近在做一個執行緒分析產品的時候,發現我們抓到了多個Attach Listener
執行緒,這讓我也很疑惑,我第一感覺是不可能,肯定是資料抓錯了,直到親眼看到了兩個同名的Attach Listener
執行緒我才不得不相信原來還真有這種情況。
問題分析
不過從Attach Listener
的實現來看,它設計的初衷不應該是一個多執行緒的設計,於是我昨晚上又翻了一遍程式碼,發現還真可能存在這種情況。舉個例子,當我們很多人同時執行jstack的時候,就可能會發生,當然有個前提是之前都沒有做過任何和attach相關的操作。
Attach Listener
執行緒預設情況下不會在JVM啟動的時候就建立,當然也有一個JVM引數可以指定在JVM啟動的時候就啟動這個執行緒,這個就不會存在我們今天討論的這個問題了,這個JVM引數是-XX:+StartAttachListener
。
當我們在執行時觸發attach機制的時候,首先會通過Signal Dispatcher
執行緒來建立Attach Listener
執行緒,程式碼如下:
在上面的圈起來的init方法裡會建立Attach Listener
執行緒,但是在init方法執行之前會通過_initialized
屬性來判斷是否需要建立執行緒,而_initialized
設定為true是在attach_listener_thread_entry
裡,這個是Attach Listener Thread
的entry,也就是當這個執行緒執行的時候執行的方法。
但是在設定_initialized=true
之前,如果有多個請求訊號發出了(比如同時又很多jstack命令觸發),可能會建立多個Attach Listener
,因為Signal Dispatcher
和Attach Listener
執行緒是非同步執行的。
問題復現
為了讓效果更明顯,我們可以在hotspot裡修改下程式碼重新編譯下再跑demo
在上面函式里加上圈起來的這段程式碼,表示在設定_initialized
屬性之前停留15s,當程式起來之後,不斷執行jstack <pid>
,最終將會看到有非常多的Attach Listener
執行緒
其實問題的根本就是有一個空檔期(設定_initialized
為true之前)可能存在多次建立執行緒的可能。
總結
總的來說,建立Attach Listener
執行緒是通過Signal Dispatcher
執行緒來建立的,但是決定Signal Dispatcher
是否可以重複建立Attach Listener
執行緒的標記是在某個Attach Listener
執行緒裡設定的,如果沒有及時設定該標記,就可能存在建立多個Attach Listener
執行緒的情況。
一起來學習吧: