本文來自: 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裏修改下代碼從新編譯下再跑demospa
在上面函數里加上圈起來的這段代碼,表示在設置_initialized
屬性以前停留15s,當進程起來以後,不斷執行jstack <pid>
,最終將會看到有很是多的Attach Listener
線程線程
其實問題的根本就是有一個空檔期(設置_initialized
爲true以前)可能存在屢次建立線程的可能。設計
總的來講,建立Attach Listener
線程是經過Signal Dispatcher
線程來建立的,可是決定Signal Dispatcher
是否能夠重複建立Attach Listener
線程的標記是在某個Attach Listener
線程裏設置的,若是沒有及時設置該標記,就可能存在建立多個Attach Listener
線程的狀況。
一塊兒來學習吧: