在 Java 程序的運行過程當中,對 JVM 和系統的監測一直是 Java 開發人員在開發過程所須要的。一直以來,Java 開發人員必須經過一些底層的 JVM API,好比 JVMPI 和 JVMTI 等,才能監測 Java 程序運行過程當中的 JVM 和系統的一系列狀況,這種方式一直以來被人所詬病,由於這須要大量的 C 程序和 JNI 調用,開發效率十分低下。因而出現了各類不一樣的專門作資源管理的程序包。爲了解決這個問題,Sun 公司也在其 Java SE 5 版本中,正式提出了 Java 管理擴展(Java Management Extensions,JMX)用來管理檢測 Java 程序(同時 JMX 也在 J2EE 1.4 中被髮布)。java
JMX 的提出,讓 JDK 中開發自檢測程序成爲可能,也提供了大量輕量級的檢測 JVM 和運行中對象 / 線程的方式,從而提升了 Java 語言本身的管理監測能力。程序員
回頁首數據庫
要了解 JMX,咱們就必須對當前的 IT 管理系統有一個初步的瞭解。隨着企業 IT 規模的不斷增加,IT 資源(IT resource)數量不斷增長,IT 資源的分佈也愈來愈分散。能夠想象,甚至對於一家只有幾百臺 PC 公司的 IT 管理人員來講,分發一個安全補丁而且保證其在每臺 PC 上的安裝,若是隻依賴人工來完成那簡直就是一場噩夢。這樣,IT 管理系統就應運而生。緩存
然而,CPU、網卡、存儲陣列是 IT 資源;OS、MS Office、Oracle database、IBM Websphere 也是 IT 資源。IT 管理系統若要對這些 IT 資源進行管理,就必須對這些管理對象有所瞭解:形形色色的 IT 資源就像是說着不一樣語言的人:Oralce 數據庫表達內存緊張的方式和 Window XP 是絕然不一樣的, 而 IT 管理系統就像建造通天塔的經理,必須精通全部的語言, 這幾乎是一個不可能完成的任務。難道 IT 管理系統是另一個通天塔嗎?固然不是!其實咱們只要給每一個 IT 資源配個翻譯就能夠了。安全
上圖分析了管理系統的基本構架模式。其中 Agent / SubAgent 起到的就是翻譯的做用:把 IT 資源報告的消息以管理系統能理解的方式傳送出去。服務器
也許讀者有會問,爲何須要 Agent 和 SubAgent 兩層體系呢?這裏有兩個現實的緣由:網絡
通常來講,管理系統會將同一物理分佈或者功能相似的 SubAgent 分組成一組,由一個共用的 Agent 加以管理。在這個 Agent 裏封裝了 1 和 2 的功能。多線程
JMX 既是 Java 管理系統的一個標準,一個規範,也是一個接口,一個框架。圖 2 展現了 JMX 的基本架構。架構
和其它的資源系統同樣,JMX 是管理系統和資源之間的一個接口,它定義了管理系統和資源之間交互的標準。javax.management.MBeanServer
實現了 Agent 的功能,以標準的方式給出了管理系統訪問 JMX 框架的接口。而javax.management.MBeans
實現了 SubAgent 的功能,以標準的方式給出了 JMX 框架訪問資源的接口。而從類庫的層次上看,JMX 包括了核心類庫 java.lang.management
和 javax.management
包。java.lang.management
包提供了基本的 VM 監控功能,而 javax.management
包則向用戶提供了擴展功能。app
JMX 使用了 Java Bean 模式來傳遞信息。通常說來,JMX 使用有名的 MBean,其內部包含了數據信息,這些信息多是:應用程序配置信息、模塊信息、系統信息、統計信息等。另外,MBean 也能夠設立可讀寫的屬性、直接操做某些函數甚至啓動 MBean 可發送的 notification 等。MBean 包括 Standard,MXBean,Dynamic,Model,Open 等幾種分類,其中最簡單是標準 MBean 和 MXBean,而咱們使用得最多的也是這兩種。MXBean 主要是 java.lang.management
使用較多,將在下一節中介紹。咱們先了解其餘一些重要的 MBean 的種類。
標準 MBean 是最簡單的一類 MBean,與動態 Bean 不一樣,它並不實現 javax.management
包中的特殊的接口。說它是標準 MBean, 是由於其向外部公開其接口的方法和普通的 Java Bean 相同,是經過 lexical,或者說 coding convention 進行的。下面咱們就用一個例子來展示,如何實現一個標準 MBean 來監控某個服務器 ServerImpl 狀態的。ServerImpl 表明了用來演示的某個 Server 的實現:
package standardbeans; public class ServerImpl { public final long startTime; public ServerImpl() { startTime = System.currentTimeMillis(); } }
而後,咱們打算使用一個標準 MBean,ServerMonitor 來監控 ServerImpl:
package standardbeans; public class ServerMonitor implements ServerMonitorMBean { private final ServerImpl target; public ServerMonitor(ServerImpl target){ this.target = target; } public long getUpTime(){ return System.currentTimeMillis() - target.startTime; } }
這裏的 ServerMonitorBean 又是怎麼回事呢? MXBean 規定了標準 MBean 也要實現一個接口,全部向外界公開的方法都要在這個接口中聲明。不然,管理系統就不能從中得到相應的信息。此外,該接口的名字也有必定的規範:即在標準 MBean 類名以後加上「MBean」後綴。若 MBean 的類名叫作 MBeansName 的話,對應的接口就要叫作 MBeansNameMBean。
對於管理系統來講,這些在 MBean 中公開的方法,最終會被 JMX 轉化成屬性(Attribute)、監聽(Listener)和調用(Invoke)的概念。若是讀者對 Java Bean 有一些瞭解的話,不難看出,public long getUpTime()
對應了 Bean 中的一個稱爲「upTime」的只讀屬性。
下面咱們就看一個模擬管理系統的例子:
package standardbeans; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.ObjectName; public class Main { private static ObjectName objectName ; private static MBeanServer mBeanServer; public static void main(String[] args) throws Exception{ init(); manage(); } private static void init() throws Exception{ ServerImpl serverImpl = new ServerImpl(); ServerMonitor serverMonitor = new ServerMonitor(serverImpl); mBeanServer = MBeanServerFactory.createMBeanServer(); objectName = new ObjectName("objectName:id=ServerMonitor1"); mBeanServer.registerMBean(serverMonitor,objectName); } private static void manage() throws Exception{ Long upTime = (Long) mBeanServer.getAttribute(objectName, "upTime"); System.out.println(upTime); } }
JMX 的核心是 MBServer。Java SE 已經提供了一個默認實現,能夠經過 MBServerFactory.createMBeanServer()
得到。每一個資源監控者(MBean)通常都會有名稱(ObjectName), 登記在 MBServer 內部的一個 Repository 中。注意,這個 ObjectName 對於每個 MBServer 必須是惟一的,只能對應於一個 MBean。(讀者有興趣的話,能夠試着再給 mBeanServer 註冊一個同名的 objectName,看看會怎麼樣。) 上述例子是在 init()
方法中完成向 MBeanServer 註冊工做的。
在管理過程當中,管理系統並不與資源或者 SubAgent 直接打交道,也就是說,這裏不會直接引用到 MBean。而是經過 MBeanServer 的getAttribute
方法取得對應 MBean 的屬性的。
可是對於不少已有的 SubAgent 實現,其 Coding Convention 並不符合標準 MBean 的要求。重構全部這些 SubAgent 以符合標準 MBean 標準既費力也不實際。JMX 中給出了動態(Dynamic) MBean 的概念,MBServer 再也不依據 Coding Convention 而是直接查詢動態 MBean 給出的元數據(meta data)以得到 MBean 的對外接口。
package dynamicbeans; import javax.management.*; import java.lang.reflect.*; public class ServerMonitor implements DynamicMBean { private final ServerImpl target; private MBeanInfo mBeanInfo; public ServerMonitor(ServerImpl target){ this.target = target; } // 實現獲取被管理的 ServerImpl 的 upTime public long upTime(){ return System.currentTimeMillis() - target.startTime; } //javax.management.MBeanServer 會經過查詢 getAttribute("Uptime") 得到 "Uptime" 屬性值 public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { if(attribute.equals("UpTime")){ return upTime(); } return null; } // 給出 ServerMonitor 的元信息。 public MBeanInfo getMBeanInfo() { if (mBeanInfo == null) { try { Class cls = this.getClass(); // 用反射得到 "upTime" 屬性的讀方法 Method readMethod = cls.getMethod("upTime", new Class[0]); // 用反射得到構造方法 Constructor constructor = cls.getConstructor(new Class[] {ServerImpl.class}); // 關於 "upTime" 屬性的元信息 : 名稱爲 UpTime,只讀屬性 ( 沒有寫方法 )。 MBeanAttributeInfo upTimeMBeanAttributeInfo = new MBeanAttributeInfo( "UpTime", "The time span since server start", readMethod, null); // 關於構造函數的元信息 MBeanConstructorInfo mBeanConstructorInfo = new MBeanConstructorInfo( "Constructor for ServerMonitor", constructor); //ServerMonitor 的元信息,爲了簡單起見,在這個例子裏, // 沒有提供 invocation 以及 listener 方面的元信息 mBeanInfo = new MBeanInfo(cls.getName(), "Monitor that controls the server", new MBeanAttributeInfo[] { upTimeMBeanAttributeInfo }, new MBeanConstructorInfo[] { mBeanConstructorInfo }, null, null); } catch (Exception e) { throw new Error(e); } } return mBeanInfo; } public AttributeList getAttributes(String[] arg0) { return null; } public Object invoke(String arg0, Object[] arg1, String[] arg2) throws MBeanException, ReflectionException { return null; } public void setAttribute(Attribute arg0) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { return; } public AttributeList setAttributes(AttributeList arg0) { return null; } }
另外還有兩類 MBean:Open MBean 和 Model MBean。實際上它們也都是動態 MBean。
Open MBean 與其它動態 MBean 的惟一區別在於,前者對其公開接口的參數和返回值有所限制 —— 只能是基本類型或者javax.management.openmbean
包內的 ArrayType、CompositeType、TarbularType 等類型。這主要是考慮到管理系統的分佈,極可能遠端管理系統甚至 MBServer 層都不具備 MBean 接口中特殊的類。
然而,普通的動態 Bean 一般缺少一些管理系統所須要的支持:好比持久化 MBean 的狀態、日誌記錄、緩存等等。若是讓用戶去一一實現這些功能確實是件枯燥無聊的工做。爲了減輕用戶的負擔,JMX 提供商都會提供不一樣的 ModelBean 實現。其中有一個接口是 Java 規範中規定全部廠商必須實現的:javax.management.modelmbean.RequiredModelBean
。經過配置 Descriptor 信息,咱們能夠定製這個 Model Bean, 指定哪些 MBean 狀態須要記入日誌、如何記錄以及是否緩存某些屬性、緩存多久等等。這裏,咱們以 RequiredModelBean 爲例討論 ModelBean。好比,咱們先來看一個例子,首先是 server 端:
package modelmbean; public class Server { private long startTime; public Server() { } public int start(){ startTime = System.currentTimeMillis(); return 0; } public long getUpTime(){ return System.currentTimeMillis() - startTime; } }
而後咱們對它的監測以下:
package modelmbean; import javax.management.*; import javax.management.modelmbean.*; public class Main { public static void main(String[] args) throws Exception{ MBeanServer mBeanServer = MBeanServerFactory.createMBeanServer(); RequiredModelMBean serverMBean = (RequiredModelMBean) mBeanServer.instantiate( "javax.management.modelmbean.RequiredModelMBean"); ObjectName serverMBeanName = new ObjectName("server: id=Server"); serverMBean.setModelMBeanInfo(getModelMBeanInfoForServer(serverMBeanName)); Server server = new Server(); serverMBean.setManagedResource(server, "ObjectReference"); ObjectInstance registeredServerMBean = mBeanServer.registerMBean((Object) serverMBean, serverMBeanName); serverMBean.invoke("start",null, null); Thread.sleep(1000); System.out.println(serverMBean.getAttribute("upTime")); Thread.sleep(5000); System.out.println(serverMBean.getAttribute("upTime")); } private static ModelMBeanInfo getModelMBeanInfoForServer(ObjectName objectName) throws Exception{ ModelMBeanAttributeInfo[] serverAttributes = new ModelMBeanAttributeInfo[1]; Descriptor upTime = new DescriptorSupport( new String[] { "name=upTime", "descriptorType=attribute", "displayName=Server upTime", "getMethod=getUpTime", }); serverAttributes[0] = new ModelMBeanAttributeInfo( "upTime", "long", "Server upTime", true, false, false, upTime); ModelMBeanOperationInfo[] serverOperations = new ModelMBeanOperationInfo[2]; Descriptor getUpTimeDesc = new DescriptorSupport( new String[] { "name=getUpTime", "descriptorType=operation", "class=modelmbean.Server", "role=operation" }); MBeanParameterInfo[] getUpTimeParms = new MBeanParameterInfo[0]; serverOperations[0] = new ModelMBeanOperationInfo("getUpTime", "get the up time of the server", getUpTimeParms, "java.lang.Long", MBeanOperationInfo.ACTION, getUpTimeDesc); Descriptor startDesc = new DescriptorSupport( new String[] { "name=start", "descriptorType=operation", "class=modelmbean.Server", "role=operation" }); MBeanParameterInfo[] startParms = new MBeanParameterInfo[0]; serverOperations[1] = new ModelMBeanOperationInfo("start", "start(): start server", startParms, "java.lang.Integer", MBeanOperationInfo.ACTION, startDesc); ModelMBeanInfo serverMMBeanInfo = new ModelMBeanInfoSupport( "modelmbean.Server", "ModelMBean for managing an Server", serverAttributes, null, serverOperations, null); //Default strategy for the MBean. Descriptor serverDescription = new DescriptorSupport( new String[] { ("name=" + objectName), "descriptorType=mbean", ("displayName=Server"), "type=modelmbean.Server", "log=T", "logFile=serverMX.log", "currencyTimeLimit=10" }); serverMMBeanInfo.setMBeanDescriptor(serverDescription); return serverMMBeanInfo; }
很明顯,和其它 MBean 相似,使用 Model MBean 的過程也是下面幾步:
惟一不一樣的是,ModelMBean 須要額外兩步 :
1.serverMBean.setModelMBeanInfo(getModelMBeanInfoForServer(serverMBeanName)); 2.serverMBean.setManagedResource(server, "ObjectReference");
第一步用於提供 serverMBean 的元數據,主要包括如下兩類
第二步指出了 ServerMBean 管理的對象,也就是說,從元數據中獲得的 Method 將施加在哪一個 Object 上。須要指出的是setManagedResource(Object o, String type);
中第二個參數是 Object 類型,能夠是 "ObjectReference"、"Handle"、"IOR"、"EJBHandle" 或 "RMIReference"。目前 SE 中的實現只支持 "ObjectReference"。筆者認爲後面幾種類型是爲了未來 JMX 管理對象擴展而設定的,可能未來 Model Bean 不只能夠管理 Plain Java Object(POJO),還可能管理 Native Resource, 並給諸如 EJB 和 RMI 對象的管理提供更多的特性。
Model Bean 與普通動態 Bean 區別在於它的元數據類型 ModelMBeanInfo 擴展了前者的 MBeanInfo,使得 ModelMBeanOperationInfo、ModelMBeanConstructor_Info、ModelMBeanAttributeInfo 和 ModelMBeanNotificationInfo 都有一個額外的元數據:javax.management.Descriptor
,它是用來設定 Model Bean 策略的。數據的存儲是典型的 "key-value" 鍵值對。不一樣的 Model Bean 實現,以及不一樣的 MBeanFeatureInfo 支持不一樣的策略特性。下面咱們就以 Attribute 爲例,看一下 RequiredModelBean 支持的策略。
首先,它最重要的 Descriptor 主要是 name、displayName 和 descriptorType,其中 name 是屬性名稱。"name" 要與對應 ModelMBeanAttributeInfo 的 name 相同。descriptorType 必須是 "attribute"。
另外,value、default、legalValues "value" 是用來設定初始值的,"default" 指當不能從 resource 中得到該屬性時的默認返回值,"legalValues" 是一組合法的屬性數據。它並不用來保證 setAttribute 的數據一致性,而是在 UI 系統,如 JConsole 中提示用戶可能的數據輸入。
在屬性訪問的 getMethod, setMethod 方法上,事實上全部對屬性的訪問都會被 delegate 給同一 MBeanInfo 中特定的 Operation。 getMethod/setMethod 給出了對應的 ModelMBeanOperationInfo 名稱。
還有一些額外的屬性,好比:persistPolicy, persistPeriod 是表明了持久化策略;currencyTimeLimit, lastUpdatedTimeStamp 緩存策略;iterable 屬性是否必須使用 iterate 來訪問。默認爲否;protocolMap 定義了與第三方系統有關的數據轉換的 data model;visibility 定義了與第三方 UI 系統有關的 MBean 如何顯示的策略;presentationString 也是定義了與第三方 UI 系統有關的 MBean 如何顯示策略,好比 "presentation=server.gif"。
事實上,策略特性有兩個層次的做用域:整個 Model Bean 和特定的 MBeanFeature。
Model Bean 的策略描述會被施加到該 Model Bean 的全部 MBeanFeature 上去,除非該 MBeanFeature 重寫了這個策略特性。
在上面的例子裏,這一個語句:
serverMMBeanInfo.setMBeanDescriptor(serverDescription);
給整個 serverMBeanInfo 設了一個策略描述 serverDescription,其中用 "currencyTimeLimit=10" 指出屬性的緩存時間是 10 秒。因此,在 Main 方法中,兩次 serverMBean.getAttribute("upTime");之間的間隔小於 10 秒就會獲得一樣的緩存值。
若是咱們不想讓 "upTime" 這個屬性被緩存,咱們能夠在它的策略描述中加入 "currencyTimeLimit=-1":
Descriptor upTime = new DescriptorSupport( new String[] { "name=upTime", "descriptorType=attribute", "displayName=Server upTime", "getMethod=getUpTime", "currencyTimeLimit=-1" // 不須要緩存 }); Descriptor getUpTimeDesc = new DescriptorSupport( new String[] { "name=getUpTime", "descriptorType=operation", "class=modelmbean.Server", "role=operation" ,"currencyTimeLimit=-1" // 不須要緩存 });
getUpTimeDesc 也要改動的緣由是 RequiredModelBean 會把獲取 upTime 屬性的工做 delegate 給 getUpTime invocation。只要其中一處使用 MBean 級的緩存策略,就無法得到實時 upTime 數據了。
JMX 的提出,爲 Java 虛擬機提供了 Java 層上的檢測機制。J2SE 中,新提出的 java.lang.management
包便是 JMX 在 JDK 的一個應用,它提供了大量的有用的接口,經過 MBean 方式,提供了對 Java 虛擬機和運行時遠端的監控和檢測方式,來幫助用戶來檢測本地或者遠端的虛擬機的運行狀況。有了 JMX 以後,咱們能夠設計一個客戶端,來檢測遠端一個正在運行的虛擬機中的線程數、線程當前的 Stack、內存管理、GC 所佔用的時間、虛擬機中的對象和當前虛擬機參數等重要的參數和運行時信息。JMX 另外的一個重要功能是對配置信息的檢測和再配置。好比,咱們能夠在遠端查看和修改當前 JVM 的 verbose 參數,以達到動態管理的目的。甚至,咱們能夠在遠端指揮 JVM 作一次 GC,這在下文中有詳細介紹。
檢測虛擬機當前的狀態老是 Java 開放人員所關心的,也正是由於如此,出現了大量的 profiler 工具來檢測當前的虛擬機狀態。從 Java SE 5 以後,在 JDK 中,咱們有了一些 Java 的虛擬機檢測 API,即 java.lang.management
包。Management 包裏面包括了許多 MXBean 的接口類和 LockInfo、MemoryUsage、MonitorInfo 和 ThreadInfo 等類。從名字能夠看出,該包提供了虛擬機內存分配、垃圾收集(GC)狀況、操做系統層、線程調度和共享鎖,甚至編譯狀況的檢測機制。這樣一來,Java 的開發人員就能夠很簡單地爲本身作一些輕量級的系統檢測,來肯定當前程序的各類狀態,以便隨時調整。
要得到這些信息,咱們首先經過 java.lang.management.ManagementFactory
這個工廠類來得到一系列的 MXBean。包括:
ClassLoadMXBean 包括一些類的裝載信息,好比有多少類已經裝載 / 卸載(unloaded),虛擬機類裝載的 verbose 選項(即命令行中的 Java – verbose:class 選項)是否打開,還能夠幫助用戶打開 / 關閉該選項。
CompilationMXBean 幫助用戶瞭解當前的編譯器和編譯狀況,該 mxbean 提供的信息很少。
相對於開放人員對 GC 的關注程度來講,該 mxbean 提供的信息十分有限,僅僅提供了 GC 的次數和 GC 花費總時間的近似值。可是這個包中還提供了三個的內存管理檢測類:MemoryManagerMXBean,MemoryMXBean 和 MemoryPoolMXBean。
這個類相對簡單,提供了內存管理類和內存池(memory pool)的名字信息。
這個類提供了整個虛擬機中內存的使用狀況,包括 Java 堆(heap)和非 Java 堆所佔用的內存,提供當前等待 finalize 的對象數量,它甚至能夠作 gc(其實是調用 System.gc)。
該信息提供了大量的信息。在 JVM 中,可能有幾個內存池,所以有對應的內存池信息,所以,在工廠類中,getMemoryPoolMXBean() 獲得是一個 MemoryPoolMXBean 的 list。每個 MemoryPoolMXBean 都包含了該內存池的詳細信息,如是否可用、當前已使用內存 / 最大使用內存值、以及設置最大內存值等等。
該類提供的是操做系統的簡單信息,如構架名稱、當前 CPU 數、最近系統負載等。
運行時信息包括當前虛擬機的名稱、提供商、版本號,以及 classpath、bootclasspath 和系統參數等等。
在 Java 這個多線程的系統中,對線程的監控是至關重要的。ThreadMXBean 就是起到這個做用。ThreadMXBean 能夠提供的信息包括各個線程的各類狀態,CPU 佔用狀況,以及整個系統中的線程情況。從 ThreadMXBean 能夠獲得某一個線程的 ThreadInfo 對象。這個對象中則包含了這個線程的全部信息。
咱們知道,management 和底層虛擬機的關係是很是緊密的。其實,有一些的是直接依靠虛擬機提供的公開 API 實現的,好比 JVMTI;而另一些則否則,很大一塊都是由虛擬機底層提供某些不公開的 API / Native Code 提供的。這樣的設計方式,保證了 management 包能夠提供足夠的信息,而且使這些信息的提供又有足夠的效率;也使 management 包和底層的聯繫很是緊密。
Management 在 Java SE 5 被提出以後,受到了歡迎。在 Java 6 當中,這個包提供更多的 API 來更好地提供信息。
Java 程序一般關注是虛擬機內部的負載、內存等情況,而不考慮整個系統的情況。可是不少狀況下,Java 程序在運行過程當中,整個計算機系統的系統負荷狀況也會對虛擬機形成必定的影響。隨着 Java 的發展,Java 程序已經覆蓋了各個行業,這一點也必須獲得關注。在之前,利用 Native 代碼來檢測系統負載每每是惟一的選擇,可是在 Java 6 當中,JDK 本身提供了一個輕量級的系統負載檢測 API,即OperatingSystemMXBean.getSystemLoadAverage()
。
固然這個 API 事實上僅僅返回一個對前一分鐘系統負載的簡單的估測。它設計的主要目標是簡單快速地估測當前系統負荷,所以它首先保證了這個 API 的效率是很是高的;也由於如此,這個 API 事實上並不適用於全部的系統。
咱們知道,同步是 Java 語言很重要的一個特性。在 Java SE 中,最主要的同步機制是依靠 synchronize 關鍵字對某一個對象加鎖實現的;在 Java SE 5 以後的版本中,concurrent 包的加入,大大強化了 Java 語言的同步能力,concurrent 提供了不少不一樣類型的鎖機制可供擴展。所以,要更好地觀測當前的虛擬機情況和不一樣線程的運行態,去觀察虛擬機中的各類鎖,以及線程與鎖的關係是很是必要的。很惋惜的是,在過去的 JDK 中,咱們並無很是方便的 API 以供使用。一個比較直接的檢測方式是查看線程的 stack trace,更爲強大全面(可是也更復雜而且效率低下)的方案是獲得一個 VM 全部對象的快照並查找之,這些策略的代價都比較大,並且每每須要編寫複雜的 Native 代碼。
JDK 6 裏提供了一些至關簡單的 API 來提供這個服務。首先了解兩個新類,LockInfo 和 MonitorInfo 這兩個類承載了鎖的信息。LockInfo 能夠是任何的 Java 鎖,包括簡單 Java 鎖和 java.util.concurrent
包中所使用的鎖(包括 AbstractOwnableSynchronizer 和 Condition 的實現類 / 子類),而 MonitorInfo 是簡單的 Java 對象所表明的鎖。要檢測一個線程所擁有的鎖和等待的鎖,首先,要獲得一個線程的 ThreadInfo,而後能夠簡單地調用:
getLockedMonitors()
返回一個全部當前線程已經掌握的鎖對象的列表。
getLockedSynchronizers()
對於使用 concurrent 包的線程,返回一個該線程所掌握的「ownable synchronizer」(即 AbstractOwnableSynchronizer 及其子類)所組成的列表。
getLockInfo()
當前線程正在等待的那個鎖對象的信息就能夠知道線程全部的鎖信息。經過這些鎖信息,咱們很方便的能夠知道當前虛擬機的全部線程的鎖信息。由此,咱們還能夠推導出更多的信息。
死鎖檢測一直以來是軟件工程師所重視的,顯然一個死鎖的系統永遠是工程師最大的夢魘。Java 程序的死鎖檢測也一直以來是 Java 程序員所頭痛的。爲了解決線程間死鎖問題,通常都有預防(代碼實現階段)和死鎖後恢復(運行時)兩種方式。之前 Java 程序員都重視前者,由於在運行態再來檢測和恢復系統是至關麻煩的,缺乏許多必要的信息;可是,對於一些比較複雜的系統,採起後者或者運行時調試死鎖信息也是很是重要的。由上面所說,如今咱們已經能夠知道每個線程所擁有和等待的鎖,所以要計算出當前系統中是否有死鎖的線程也是可行的了。固然,Java 6 裏面也提供了一個 API 來完成這個功能,即:
ThreadMXBean.findDeadlockedThreads()
這個函數的功能就是檢測出當前系統中已經死鎖的線程。固然,這個功能複雜,所以比較費時。基本上僅僅將之用於調試,以便對複雜系統線程調用的改進。
JMX 在 Java SE 5/6 中的功能已經至關強大,可是距離 Java 程序開發人員的要求仍是有一段距離,所以 Sun 公司已經向 JCP 提出了 JSR 255 (JMX API 2.0 版本)來擴充和進一步發展 JMX,並但願這個 JSR 將在 Java SE 7 中實現。在這個文檔中,新的 JMX 2.0 將着重於:
具體的擴展可能包括:
能夠看到,JMX 的進一步發展主要關注的是可擴展性、動態性和易用性等 Java 用戶很是關注的方面。
在 Java SE 5 出現的 JMX 在 Java SE 6 中有了更多的功能和擴展能力,這很好地適應了 Java 語言的發展和用戶的要求,讓 Java 的監測、管理的的功能更增強大。
來源:http://www.ibm.com/developerworks/cn/java/j-lo-jse63/