前言
在 java 程序的運(yùn)行過(guò)程中,對(duì) JVM 和系統(tǒng)的監(jiān)測(cè)一直是 Java 開發(fā)人員在開發(fā)過(guò)程所需要的。一直以來(lái),Java 開發(fā)人員必須通過(guò)一些底層的 JVM API,比如 JVMPI 和 JVMTI 等,才能監(jiān)測(cè) Java 程序運(yùn)行過(guò)程中的 JVM 和系統(tǒng)的一系列情況,這種方式一直以來(lái)被人所詬病,因?yàn)檫@需要大量的 C 程序和 JNI 調(diào)用,開發(fā)效率十分低下。于是出現(xiàn)了各種不同的專門做資源治理的程序包。為了解決這個(gè)問(wèn)題,Sun 公司也在其 Java SE 5 版本中,正式提出了 Java 治理擴(kuò)展(Java Management Extensions,JMX)用來(lái)治理檢測(cè) Java 程序(同時(shí) JMX 也在 J2EE 1.4 中被發(fā)布)。
JMX 的提出,讓 JDK 中開發(fā)自檢測(cè)程序成為可能,也提供了大量輕量級(jí)的檢測(cè) JVM 和運(yùn)行中對(duì)象/線程的方式,從而提高了 Java 語(yǔ)言自己的治理監(jiān)測(cè)能力。
JMX 和系統(tǒng)治理
治理系統(tǒng)(Management System)
要了解 JMX,我們就必須對(duì)當(dāng)前的 IT 治理系統(tǒng)有一個(gè)初步的了解。隨著企業(yè) IT 規(guī)模的不斷增長(zhǎng),IT 資源(IT resource)數(shù)量不斷增加,IT 資源的分布也越來(lái)越分散。可以想象,甚至對(duì)于一家只有幾百臺(tái) PC 公司的 IT 治理人員來(lái)說(shuō),分發(fā)一個(gè)安全補(bǔ)丁并且保證其在每臺(tái) PC 上的安裝,假如只依靠人工來(lái)完成那簡(jiǎn)直就是一場(chǎng)噩夢(mèng)。這樣,IT 治理系統(tǒng)就應(yīng)運(yùn)而生。
然而,CPU、網(wǎng)卡、存儲(chǔ)陣列是 IT 資源;OS、MS Office、Oracle database、IBM Websphere 也是 IT 資源。IT 治理系統(tǒng)若要對(duì)這些 IT 資源進(jìn)行治理,就必須對(duì)這些治理對(duì)象有所了解:形形色色的 IT 資源就像是說(shuō)著不同語(yǔ)言的人:Oralce 數(shù)據(jù)庫(kù)表達(dá)內(nèi)存緊張的方式和 Window XP 是絕然不同的, 而 IT 治理系統(tǒng)就像建造通天塔的經(jīng)理,必須精通所有的語(yǔ)言, 這幾乎是一個(gè)不可能完成的任務(wù)。難道 IT 治理系統(tǒng)是另外一個(gè)通天塔嗎?當(dāng)然不是!其實(shí)我們只要給每個(gè) IT 資源配個(gè)翻譯就可以了。
治理系統(tǒng)的構(gòu)架
圖 1. 治理系統(tǒng)構(gòu)架
上圖分析了治理系統(tǒng)的基本構(gòu)架模式。其中 Agent / SubAgent 起到的就是翻譯的作用:把 IT 資源報(bào)告的消息以治理系統(tǒng)能理解的方式傳送出去。
也許讀者有會(huì)問(wèn),為什么需要 Agent 和 SubAgent 兩層體系呢?這里有兩個(gè)現(xiàn)實(shí)的原因:
一般來(lái)說(shuō),治理系統(tǒng)會(huì)將同一物理分布或者功能類似的 SubAgent 分組成一組,由一個(gè)共用的 Agent 加以治理。在這個(gè) Agent 里封裝了 1 和 2 的功能。
JMX 和治理系統(tǒng)
JMX 既是 Java 治理系統(tǒng)的一個(gè)標(biāo)準(zhǔn),一個(gè)規(guī)范,也是一個(gè)接口,一個(gè)框架。圖 2 展示了 JMX 的基本架構(gòu)。
圖 2. JMX 構(gòu)架
和其它的資源系統(tǒng)一樣,JMX 是治理系統(tǒng)和資源之間的一個(gè)接口,它定義了治理系統(tǒng)和資源之間交互的標(biāo)準(zhǔn)。>javax.management.MBeanServer 實(shí)現(xiàn)了 Agent 的功能,以標(biāo)準(zhǔn)的方式給出了治理系統(tǒng)訪問(wèn) JMX 框架的接口。而 >javax.management.MBeans 實(shí)現(xiàn)了 SubAgent 的功能,以標(biāo)準(zhǔn)的方式給出了 JMX 框架訪問(wèn)資源的接口。而從類庫(kù)的層次上看,JMX 包括了核心類庫(kù) >java.lang.management 和 >javax.management 包。>java.lang.management 包提供了基本的 VM 監(jiān)控功能,而 >javax.management 包則向用戶提供了擴(kuò)展功能。
JMX 的基本框架
JMX 使用了 Java Bean 模式來(lái)傳遞信息。一般說(shuō)來(lái),JMX 使用有名的 MBean,其內(nèi)部包含了數(shù)據(jù)信息,這些信息可能是:應(yīng)用程序配置信息、模塊信息、系統(tǒng)信息、統(tǒng)計(jì)信息等。另外,MBean 也可以設(shè)立可讀寫的屬性、直接操作某些函數(shù)甚至啟動(dòng) MBean 可發(fā)送的 notification 等。MBean 包括 Standard,MXBean,Dynamic,Model,Open 等幾種分類,其中最簡(jiǎn)單是標(biāo)準(zhǔn) MBean 和 MXBean,而我們使用得最多的也是這兩種。MXBean 主要是 >java.lang.management 使用較多,將在下一節(jié)中介紹。我們先了解其他一些重要的 MBean 的種類。
標(biāo)準(zhǔn) MBean
標(biāo)準(zhǔn) MBean 是最簡(jiǎn)單的一類 MBean,與動(dòng)態(tài) Bean 不同,它并不實(shí)現(xiàn) >javax.management 包中的非凡的接口。說(shuō)它是標(biāo)準(zhǔn) MBean, 是因?yàn)槠湎蛲獠抗_其接口的方法和普通的 Java Bean 相同,是通過(guò) lexical,或者說(shuō) coding convention 進(jìn)行的。下面我們就用一個(gè)例子來(lái)展現(xiàn),如何實(shí)現(xiàn)一個(gè)標(biāo)準(zhǔn) MBean 來(lái)監(jiān)控某個(gè)服務(wù)器 ServerImpl 狀態(tài)的。ServerImpl 代表了用來(lái)演示的某個(gè) Server 的實(shí)現(xiàn):
package standardbeans; public class ServerImpl { public final long startTime; public ServerImpl() { startTime = System.currentTimeMillis(); } } 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; } } 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); } } 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; } //實(shí)現(xiàn)獲取被治理的 ServerImpl 的 upTime public long upTime(){ return System.currentTimeMillis() - target.startTime; } //javax.management.MBeanServer 會(huì)通過(guò)查詢 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]); //用反射獲得構(gòu)造方法 ConstrUCtor constructor = cls.getConstructor(new Class[] {ServerImpl.class}); //關(guān)于 "upTime" 屬性的元信息:名稱為 UpTime,只讀屬性(沒(méi)有寫方法)。 MBeanAttributeInfo upTimeMBeanAttributeInfo = new MBeanAttributeInfo( "UpTime", "The time span since server start", readMethod, null); //關(guān)于構(gòu)造函數(shù)的元信息 MBeanConstructorInfo mBeanConstructorInfo = new MBeanConstructorInfo( "Constructor for ServerMonitor", constructor); //ServerMonitor 的元信息,為了簡(jiǎn)單起見,在這個(gè)例子里, //沒(méi)有提供 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; } } 其它動(dòng)態(tài) MBean
另外還有兩類 MBean:Open MBean 和 Model MBean。實(shí)際上它們也都是動(dòng)態(tài) MBean。
Open MBean 與其它動(dòng)態(tài) MBean 的唯一區(qū)別在于,前者對(duì)其公開接口的參數(shù)和返回值有所限制 —— 只能是基本類型或者 >javax.management.openmbean 包內(nèi)的 ArrayType、CompositeType、TarbularType 等類型。這主要是考慮到治理系統(tǒng)的分布,很可能遠(yuǎn)端治理系統(tǒng)甚至 MBServer 層都不具有 MBean 接口中非凡的類。
Model Bean
然而,普通的動(dòng)態(tài) Bean 通常缺乏一些治理系統(tǒng)所需要的支持:比如持久化 MBean 的狀態(tài)、日志記錄、緩存等等。假如讓用戶去一一實(shí)現(xiàn)這些功能確實(shí)是件枯燥無(wú)聊的工作。為了減輕用戶的負(fù)擔(dān),JMX 提供商都會(huì)提供不同的 ModelBean 實(shí)現(xiàn)。其中有一個(gè)接口是 Java 規(guī)范中規(guī)定所有廠商必須實(shí)現(xiàn)的::>javax.management.modelmbean.RequiredModelBean。通過(guò)配置 Descriptor 信息,我們可以定制這個(gè) Model Bean, 指定哪些 MBean 狀態(tài)需要記入日志、如何記錄以及是否緩存某些屬性、緩存多久等等。這里,我們以 RequiredModelBean 為例討論 ModelBean。比如,我們先來(lái)看一個(gè)例子,首先是 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; } 唯一不同的是,ModelMBean 需要額外兩步:
1.serverMBean.setModelMBeanInfo(getModelMBeanInfoForServer(serverMBeanName)); 2.serverMBean.setManagedResource(server, "ObjectReference");
第二步指出了 ServerMBean 治理的對(duì)象,也就是說(shuō),從元數(shù)據(jù)中得到的 Method 將施加在哪個(gè) Object 上。需要指出的是 >setManagedResource(Object o, String type); 中第二個(gè)參數(shù)是 Object 類型,可以是 "ObjectReference"、"Handle"、"IOR"、"EJBHandle" 或 "RMIReference"。目前 SE 中的實(shí)現(xiàn)只支持 "ObjectReference"。筆者認(rèn)為后面幾種類型是為了將來(lái) JMX 治理對(duì)象擴(kuò)展而設(shè)定的,可能將來(lái) Model Bean 不僅可以治理 Plain Java Object(POJO),還可能治理 Native Resource, 并給諸如 EJB 和 RMI 對(duì)象的治理提供更多的特性。
Model Bean 與普通動(dòng)態(tài) Bean 區(qū)別在于它的元數(shù)據(jù)類型 ModelMBeanInfo 擴(kuò)展了前者的 MBeanInfo,使得 ModelMBeanOperationInfo、ModelMBeanConstructor_Info、ModelMBeanAttributeInfo 和 ModelMBeanNotificationInfo 都有一個(gè)額外的元數(shù)據(jù):>javax.management.Descriptor,它是用來(lái)設(shè)定 Model Bean 策略的。數(shù)據(jù)的存儲(chǔ)是典型的 "key-value" 鍵值對(duì)。不同的 Model Bean 實(shí)現(xiàn),以及不同的 MBeanFeatureInfo 支持不同的策略特性。下面我們就以 Attribute 為例,看一下 RequiredModelBean 支持的策略。
首先,它最重要的 Descriptor 主要是 name、displayName 和 descriptorType,其中 name 是屬性名稱。"name" 要與對(duì)應(yīng) ModelMBeanAttributeInfo 的 name 相同。descriptorType 必須是 "attribute"。
另外,value、default、legalValues "value" 是用來(lái)設(shè)定初始值的,"default" 指當(dāng)不能從 resource 中獲得該屬性時(shí)的默認(rèn)返回值,"legalValues" 是一組合法的屬性數(shù)據(jù)。它并不用來(lái)保證 setAttribute 的數(shù)據(jù)一致性,而是在 UI 系統(tǒng),如 JConsole 中提示用戶可能的數(shù)據(jù)輸入。
在屬性訪問(wèn)的 getMethod, setMethod 方法上,事實(shí)上所有對(duì)屬性的訪問(wèn)都會(huì)被 delegate 給同一 MBeanInfo 中特定的 Operation。 getMethod/setMethod 給出了對(duì)應(yīng)的 ModelMBeanOperationInfo 名稱。
還有一些額外的屬性,比如:persistPolicy, persistPeriod 是代表了持久化策略;currencyTimeLimit, lastUpdatedTimeStamp 緩存策略;iterable 屬性是否必須使用 iterate 來(lái)訪問(wèn)。默認(rèn)為否;protocolMap 定義了與第三方系統(tǒng)有關(guān)的數(shù)據(jù)轉(zhuǎn)換的 data model;visibility 定義了與第三方 UI 系統(tǒng)有關(guān)的 MBean 如何顯示的策略;presentationString 也是定義了與第三方 UI 系統(tǒng)有關(guān)的 MBean 如何顯示策略,比如 "presentation=server.gif"。
事實(shí)上,策略特性有兩個(gè)層次的作用域:整個(gè) Model Bean 和特定的 MBeanFeature。
Model Bean 的策略描述會(huì)被施加到該 Model Bean 的所有 MBeanFeature 上去,除非該 MBeanFeature 重寫了這個(gè)策略特性。
在上面的例子里,這一個(gè)語(yǔ)句:
serverMMBeanInfo.setMBeanDescriptor(serverDescription);給整個(gè) serverMBeanInfo 設(shè)了一個(gè)策略描述 serverDescription,其中用 "currencyTimeLimit=10" 指出屬性的緩存時(shí)間是 10 秒。所以,在 Main 方法中,兩次 serverMBean.getAttribute("upTime");之間的間隔小于 10 秒就會(huì)得到同樣的緩存值。
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" //不需要緩存 }); java.lang.management 和虛擬機(jī)的關(guān)系
我們知道,management 和底層虛擬機(jī)的關(guān)系是非常緊密的。其實(shí),有一些的是直接依靠虛擬機(jī)提供的公開 API 實(shí)現(xiàn)的,比如 JVMTI;而另外一些則不然,很大一塊都是由虛擬機(jī)底層提供某些不公開的 API / Native Code 提供的。這樣的設(shè)計(jì)方式,保證了 management 包可以提供足夠的信息,并且使這些信息的提供又有足夠的效率;也使 management 包和底層的聯(lián)系非常緊密。
Java 6 中的 API 改進(jìn)
Management 在 Java SE 5 被提出之后,受到了歡迎。在 Java 6 當(dāng)中,這個(gè)包提供更多的 API 來(lái)更好地提供信息。
OperatingSystemMXBean. getSystemLoadAverage()
Java 程序通常關(guān)注是虛擬機(jī)內(nèi)部的負(fù)載、內(nèi)存等狀況,而不考慮整個(gè)系統(tǒng)的狀況。但是很多情況下,Java 程序在運(yùn)行過(guò)程中,整個(gè)計(jì)算機(jī)系統(tǒng)的系統(tǒng)負(fù)荷情況也會(huì)對(duì)虛擬機(jī)造成一定的影響。隨著 Java 的發(fā)展,Java 程序已經(jīng)覆蓋了各個(gè)行業(yè),這一點(diǎn)也必須得到關(guān)注。在以前,利用 Native 代碼來(lái)檢測(cè)系統(tǒng)負(fù)載往往是唯一的選擇,但是在 Java 6 當(dāng)中,JDK 自己提供了一個(gè)輕量級(jí)的系統(tǒng)負(fù)載檢測(cè) API,即 OperatingSystemMXBean.getSystemLoadAverage()。
當(dāng)然這個(gè) API 事實(shí)上僅僅返回一個(gè)對(duì)前一分鐘系統(tǒng)負(fù)載的簡(jiǎn)單的估測(cè)。它設(shè)計(jì)的主要目標(biāo)是簡(jiǎn)單快速地估測(cè)當(dāng)前系統(tǒng)負(fù)荷,因此它首先保證了這個(gè) API 的效率是非常高的;也因?yàn)槿绱耍@個(gè) API 事實(shí)上并不適用于所有的系統(tǒng)。
鎖檢測(cè)
我們知道,同步是 Java 語(yǔ)言很重要的一個(gè)特性。在 Java SE 中,最主要的同步機(jī)制是依靠 synchronize 要害字對(duì)某一個(gè)對(duì)象加鎖實(shí)現(xiàn)的;在 Java SE 5 之后的版本中,concurrent 包的加入,大大強(qiáng)化了 Java 語(yǔ)言的同步能力,concurrent 提供了很多不同類型的鎖機(jī)制可供擴(kuò)展。因此,要更好地觀測(cè)當(dāng)前的虛擬機(jī)狀況和不同線程的運(yùn)行態(tài),去觀察虛擬機(jī)中的各種鎖,以及線程與鎖的關(guān)系是非常必要的。很可惜的是,在過(guò)去的 JDK 中,我們并沒(méi)有非常方便的 API 以供使用。一個(gè)比較直接的檢測(cè)方式是查看線程的 stack trace,更為強(qiáng)大全面(但是也更復(fù)雜并且效率低下)的方案是得到一個(gè) VM 所有對(duì)象的快照并查找之,這些策略的代價(jià)都比較大,而且往往需要編寫復(fù)雜的 Native 代碼。
JDK 6 里提供了一些相當(dāng)簡(jiǎn)單的 API 來(lái)提供這個(gè)服務(wù)。首先了解兩個(gè)新類,LockInfo 和 MonitorInfo 這兩個(gè)類承載了鎖的信息。LockInfo 可以是任何的 Java 鎖,包括簡(jiǎn)單 Java 鎖和 >java.util.concurrent 包中所使用的鎖(包括 AbstractOwnableSynchronizer 和 Condition 的實(shí)現(xiàn)類/子類),而 MonitorInfo 是簡(jiǎn)單的 Java 對(duì)象所代表的鎖。要檢測(cè)一個(gè)線程所擁有的鎖和等待的鎖,首先,要得到一個(gè)線程的 ThreadInfo,然后可以簡(jiǎn)單地調(diào)用:
死鎖檢測(cè)
死鎖檢測(cè)一直以來(lái)是軟件工程師所重視的,顯然一個(gè)死鎖的系統(tǒng)永遠(yuǎn)是工程師最大的夢(mèng)魘。Java 程序的死鎖檢測(cè)也一直以來(lái)是 Java 程序員所頭痛的。為了解決線程間死鎖問(wèn)題,一般都有預(yù)防(代碼實(shí)現(xiàn)階段)和死鎖后恢復(fù)(運(yùn)行時(shí))兩種方式。以前 Java 程序員都重視前者,因?yàn)樵谶\(yùn)行態(tài)再來(lái)檢測(cè)和恢復(fù)系統(tǒng)是相當(dāng)麻煩的,缺少許多必要的信息;但是,對(duì)于一些比較復(fù)雜的系統(tǒng),采取后者或者運(yùn)行時(shí)調(diào)試死鎖信息也是非常重要的。由上面所說(shuō),現(xiàn)在我們已經(jīng)可以知道每一個(gè)線程所擁有和等待的鎖,因此要計(jì)算出當(dāng)前系統(tǒng)中是否有死鎖的線程也是可行的了。當(dāng)然,Java 6 里面也提供了一個(gè) API 來(lái)完成這個(gè)功能,即:
未來(lái)的發(fā)展
JMX 在 Java SE 5/6 中的功能已經(jīng)相當(dāng)強(qiáng)大,但是距離 Java 程序開發(fā)人員的要求還是有一段距離,因此 Sun 公司已經(jīng)向 JCP 提出了 JSR 255 (JMX API 2.0 版本)來(lái)擴(kuò)充和進(jìn)一步發(fā)展 JMX,并希望這個(gè) JSR 將在 Java SE 7 中實(shí)現(xiàn)。在這個(gè)文檔中,新的 JMX 2.0 將著重于:
具體的擴(kuò)展可能包括:
可以看到,JMX 的進(jìn)一步發(fā)展主要關(guān)注的是可擴(kuò)展性、動(dòng)態(tài)性和易用性等 Java 用戶非常關(guān)注的方面。
總結(jié)
在 Java SE 5 出現(xiàn)的 JMX 在 Java SE 6 中有了更多的功能和擴(kuò)展能力,這很好地適應(yīng)了 Java 語(yǔ)言的發(fā)展和用戶的要求,讓 Java 的監(jiān)測(cè)、治理的的功能更加強(qiáng)大。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注