年底Sun 公司發布了 Java Standard Edition (Java SE )的最終正式版代號 Mustang(野馬)跟 Tiger(Java SE )相比Mustang 在性能方面有了不錯的提升與 Tiger 在 API 庫方面的大幅度加強相比雖然 Mustang 在 API 庫方面的新特性顯得不太多但是也提供了許多實用和方便的功能在腳本WebServiceXML編譯器 API數據庫JMX網絡和 Instrumentation 方面都有不錯的新特性和功能加強 本系列 文章主要介紹 Java SE 在 API 庫方面的部分新特性通過一些例子和講解幫助開發者在編程實踐當中更好的運用 Java SE 提高開發效率
本文是其中的第三篇介紹了 Java 管理擴展(Java Management ExtensionJMX) 架構及其框架以及在 Java SE 中新引入的 JMX API —— javalangmanagement 包 最後作者講述了此 API 在 Java SE 中的相關改進和對未來版本的展望
前言
在 Java 程序的運行過程中對 JVM 和系統的監測一直是 Java 開發人員在開發過程所需要的一直以來Java 開發人員必須通過一些底層的 JVM API比如 JVMPI 和 JVMTI 等才能監測 Java 程序運行過程中的 JVM 和系統的一系列情況這種方式一直以來被人所诟病因為這需要大量的 C 程序和 JNI 調用開發效率十分低下於是出現了各種不同的專門做資源管理的程序包為了解決這個問題Sun 公司也在其 Java SE 版本中正式提出了 Java 管理擴展(Java Management ExtensionsJMX)用來管理檢測 Java 程序(同時 JMX 也在 JEE 中被發布)
JMX 的提出讓 JDK 中開發自檢測程序成為可能也提供了大量輕量級的檢測 JVM 和運行中對象/線程的方式從而提高了 Java 語言自己的管理監測能力
JMX 和系統管理
管理系統(Management System)
要 了解 JMX我們就必須對當前的 IT 管理系統有一個初步的了解隨著企業 IT 規模的不斷增長IT 資源(IT resource)數量不斷增加IT 資源的分布也越來越分散可以想象甚至對於一家只有幾百台 PC 公司的 IT 管理人員來說分發一個安全補丁並且保證其在每台 PC 上的安裝如果只依賴人工來完成那簡直就是一場噩夢這樣IT 管理系統就應運而生
然而CPU網卡存儲陣列是 IT 資源OSMS OfficeOracle databaseIBM Websphere 也是 IT 資源IT 管理系統若要對這些 IT 資源進行管理就必須對這些管理對象有所了解形形色色的 IT 資源就像是說著不同語言的人Oralce 數據庫表達內存緊張的方式和 Window XP 是絕然不同的 而 IT 管理系統就像建造通天塔的經理必須精通所有的語言 這幾乎是一個不可能完成的任務難道 IT 管理系統是另外一個通天塔嗎?當然不是!其實我們只要給每個 IT 資源配個翻譯就可以了
管理系統的構架
圖 管理系統構架
上圖分析了管理系統的基本構架模式其中 Agent / SubAgent 起到的就是翻譯的作用把 IT 資源報告的消息以管理系統能理解的方式傳送出去
也許讀者有會問為什麼需要 Agent 和 SubAgent 兩層體系呢?這裡有兩個現實的原因
管理系統一般是一個中央控制的控制軟件而 SubAgent 直接監控一些資源往往和這些資源分布在同一物理位置當這些 SubAgent 把狀態信息傳輸到管理系統或者傳達管理系統的控制指令的時候需要提供一些網絡傳輸的功能
管理系統的消息是有一定規范的消息的翻譯本身是件復雜而枯燥的事情
一般來說管理系統會將同一物理分布或者功能類似的 SubAgent 分組成一組由一個共用的 Agent 加以管理在這個 Agent 裡封裝了 和 的功能
JMX 和管理系統
JMX 既是 Java 管理系統的一個標准一個規范也是一個接口一個框架圖 展示了 JMX 的基本架構
圖 JMX 構架
和其它的資源系統一樣JMX 是管理系統和資源之間的一個接口它定義了管理系統和資源之間交互的標准javaxmanagementMBeanServer 實現了 Agent 的功能以標准的方式給出了管理系統訪問 JMX 框架的接口而 javaxmanagementMBeans 實現了 SubAgent 的功能以標准的方式給出了 JMX 框架訪問資源的接口而從類庫的層次上看JMX 包括了核心類庫 javalangmanagement 和 javaxmanagement 包javalangmanagement 包提供了基本的 VM 監控功能而 javaxmanagement 包則向用戶提供了擴展功能
JMX 的基本框架
JMX 使用了 Java Bean 模式來傳遞信息一般說來JMX 使用有名的 MBean其內部包含了數據信息這些信息可能是應用程序配置信息模塊信息系統信息統計信息等另外MBean 也可以設立可讀寫的屬性直接操作某些函數甚至啟動 MBean 可發送的 notification 等MBean 包括 StandardMXBeanDynamicModelOpen 等幾種分類其中最簡單是標准 MBean 和 MXBean而我們使用得最多的也是這兩種MXBean 主要是 javalangmanagement 使用較多將在下一節中介紹我們先了解其他一些重要的 MBean 的種類
標准 MBean
標准 MBean 是最簡單的一類 MBean與動態 Bean 不同它並不實現 javaxmanagement 包中的特殊的接口說它是標准 MBean 是因為其向外部公開其接口的方法和普通的 Java Bean 相同是通過 lexical或者說 coding convention 進行的下面我們就用一個例子來展現如何實現一個標准 MBean 來監控某個服務器 ServerImpl 狀態的ServerImpl 代表了用來演示的某個 Server 的實現
package standardbeans;
public class ServerImpl {
public final long startTime;
public ServerImpl() {
startTime = SystemcurrentTimeMillis();
}
}
然後我們打算使用一個標准 MBeanServerMonitor 來監控 ServerImpl
package standardbeans;
public class ServerMonitor implements ServerMonitorMBean {
private final ServerImpl target;
public ServerMonitor(ServerImpl target){
thistarget = target;
}
public long getUpTime(){
return SystemcurrentTimeMillis() targetstartTime;
}
}
這裡的 ServerMonitorBean 又是怎麼回事呢?MXBean 規定了標准 MBean 也要實現一個接口所有向外界公開的方法都要在這個接口中聲明否則管理系統就不能從中獲得相應的信息此外該接口的名字也有一定的規范即在標准 MBean 類名之後加上MBean後綴若 MBean 的類名叫做 MBeansName 的話對應的接口就要叫做 MBeansNameMBean
對於管理系統來說這些在 MBean 中公開的方法最終會被 JMX 轉化成屬性(Attribute)監聽(Listener)和調用(Invoke)的概念如果讀者對 Java Bean 有一些了解的話不難看出public long getUpTime() 對應了 Bean 中的一個稱為upTime的只讀屬性
下面我們就看一個模擬管理系統的例子
package standardbeans;
import javaxmanagementMBeanServer;
import javaxmanagementMBeanServerFactory;
import javaxmanagementObjectName;
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 = MBeanServerFactorycreateMBeanServer();
objectName = new ObjectName(objectName:id=ServerMonitor);
mBeanServerregisterMBean(serverMonitorobjectName);
}
private static void manage() throws Exception{
Long upTime = (Long) mBeanServergetAttribute(objectName
upTime);
Systemoutprintln(upTime);
}
}
JMX 的核心是 MBServerJava SE 已經提供了一個默認實現可以通過 MBServerFactorycreateMBeanServer() 獲得每個資源監控者(MBean)一般都會有名稱(ObjectName) 登記在 MBServer 內部的一個 Repository 中注意這個 ObjectName 對於每一個 MBServer 必須是唯一的只能對應於一個 MBean(讀者有興趣的話可以試著再給 mBeanServer 注冊一個同名的 objectName看看會怎麼樣) 上述例子是在 init() 方法中完成向 MBeanServer 注冊工作的
在管理過程中管理系統並不與資源或者 SubAgent 直接打交道也就是說這裡不會直接引用到 MBean而是通過 MBeanServer 的 getAttribute 方法取得對應 MBean 的屬性的
動態 MBean
但 是對於很多已有的 SubAgent 實現其 Coding Convention 並不符合標准 MBean 的要求重構所有這些 SubAgent 以符合標准 MBean 標准既費力也不實際JMX 中給出了動態(Dynamic) MBean 的概念MBServer 不再依據 Coding Convention 而是直接查詢動態 MBean 給出的元數據(meta data)以獲得 MBean 的對外接口
package dynamicbeans;
import javaxmanagement*;
import javalangreflect*;
public class ServerMonitor implements DynamicMBean {
private final ServerImpl target;
private MBeanInfo mBeanInfo;
public ServerMonitor(ServerImpl target){
thistarget = target;
}
//實現獲取被管理的 ServerImpl 的 upTime
public long upTime(){
return SystemcurrentTimeMillis() targetstartTime;
}
//javaxmanagementMBeanServer 會通過查詢 getAttribute(Uptime) 獲得 Uptime 屬性值
public Object getAttribute(String attribute) throws AttributeNotFoundException
MBeanException ReflectionException {
if(attributeequals(UpTime)){
return upTime();
}
return null;
}
//給出 ServerMonitor 的元信息
public MBeanInfo getMBeanInfo() {
if (mBeanInfo == null) {
try {
Class cls = thisgetClass();
//用反射獲得 upTime 屬性的讀方法
Method readMethod = clsgetMethod(upTime new Class[]);
//用反射獲得構造方法
Constructor constructor = clsgetConstructor(new Class[]
{ServerImplclass});
//關於 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(clsgetName()
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[] arg) {
return null;
}
public Object invoke(String arg Object[] arg String[] arg)
throws MBeanException
ReflectionException {
return null;
}
public void setAttribute(Attribute arg) throws AttributeNotFoundException
InvalidAttributeValueException MBeanException ReflectionException {
return;
}
public AttributeList setAttributes(AttributeList arg) {
return null;
}
}
其它動態 MBean
另外還有兩類 MBeanOpen MBean 和 Model MBean實際上它們也都是動態 MBean
Open MBean 與其它動態 MBean 的唯一區別在於前者對其公開接口的參數和返回值有所限制 —— 只能是基本類型或者 javaxmanagementopenmbean 包內的 ArrayTypeCompositeTypeTarbularType 等類型這主要是考慮到管理系統的分布很可能遠端管理系統甚至 MBServer 層都不具有 MBean 接口中特殊的類
Model Bean
然而普通的動態 Bean 通常缺乏一些管理系統所需要的支持比如持久化 MBean 的狀態日志記錄緩存等等如果讓用戶去一一實現這些功能確實是件枯燥無聊的工作為了減輕用戶的負擔JMX 提供商都會提供不同的 ModelBean 實現其中有一個接口是 Java 規范中規定所有廠商必須實現的javaxmanagementmodelmbeanRequiredModelBean 通過配置 Descriptor 信息我們可以定制這個 Model Bean 指定哪些 MBean 狀態需要記入日志如何記錄以及是否緩存某些屬性緩存多久等等這裡我們以 RequiredModelBean 為例討論 ModelBean比如我們先來看一個例子首先是 server 端
package modelmbean;
public class Server {
private long startTime;
public Server() { }
public int start(){
startTime = SystemcurrentTimeMillis();
return ;
}
public long getUpTime(){
return SystemcurrentTimeMillis() startTime;
}
}
然後我們對它的監測如下
package modelmbean;
import javaxmanagement*;
import javaxmanagementmodelmbean*;
public class Main {
public static void main(String[] args) throws Exception{
MBeanServer mBeanServer = MBeanServerFactorycreateMBeanServer();
RequiredModelMBean serverMBean =
(RequiredModelMBean) mBeanServerinstantiate(
javaxmanagementmodelmbeanRequiredModelMBean);
ObjectName serverMBeanName =
new ObjectName(server: id=Server);
serverMBeansetModelMBeanInfo(getModelMBeanInfoForServer(serverMBeanName));
Server server = new Server();
serverMBeansetManagedResource(server ObjectReference);
ObjectInstance registeredServerMBean =
mBeanServerregisterMBean((Object) serverMBean serverMBeanName);
serverMBeaninvoke(startnull null);
Threadsleep();
Systemoutprintln(serverMBeangetAttribute(upTime));
Threadsleep();
Systemoutprintln(serverMBeangetAttribute(upTime));
}
private static ModelMBeanInfo getModelMBeanInfoForServer(ObjectName objectName)
throws Exception{
ModelMBeanAttributeInfo[] serverAttributes =
new ModelMBeanAttributeInfo[];
Descriptor upTime =
new DescriptorSupport(
new String[] {
name=upTime
descriptorType=attribute
displayName=Server upTime
getMethod=getUpTime
});
serverAttributes[] =
new ModelMBeanAttributeInfo(
upTime
long
Server upTime
true
false
false
upTime);
ModelMBeanOperationInfo[] serverOperations =
new ModelMBeanOperationInfo[];
Descriptor getUpTimeDesc =
new DescriptorSupport(
new String[] {
name=getUpTime
descriptorType=operation
class=modelmbeanServer
role=operation
});
MBeanParameterInfo[] getUpTimeParms = new MBeanParameterInfo[];
serverOperations[] = new ModelMBeanOperationInfo(getUpTime
get the up time of the server
getUpTimeParms
javalangLong
MBeanOperationInfoACTION
getUpTimeDesc);
Descriptor startDesc =
new DescriptorSupport(
new String[] {
name=start
descriptorType=operation
class=modelmbeanServer
role=operation
});
MBeanParameterInfo[] startParms = new MBeanParameterInfo[];
serverOperations[] = new ModelMBeanOperationInfo(start
start(): start server
startParms
javalangInteger
MBeanOperationInfoACTION
startDesc);
ModelMBeanInfo serverMMBeanInfo =
new ModelMBeanInfoSupport(
modelmbeanServer
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=modelmbeanServer
log=T
logFile=serverMXlog
currencyTimeLimit= });
serverMMBeanInfosetMBeanDescriptor(serverDescription);
return serverMMBeanInfo;
}
很明顯和其它 MBean 類似使用 Model MBean 的過程也是下面幾步
創建一個 MBServermBeanServe
獲得管理資源用的 MBeanserverBean
給這個 MBean 一個 ObjectNameserverMBeanName
將 serverBean 以 serverMBeanName 注冊到 mBeanServer 上去
唯一不同的是ModelMBean 需要額外兩步:
serverMBeansetModelMBeanInfo(getModelMBeanInfoForServer(serverMBeanName));
serverMBeansetManagedResource(server ObjectReference);
第一步用於提供 serverMBean 的元數據主要包括以下兩類
類似於普通的動態 MBean需要 MBean 的 AttributeInvocationNotification 的類型/反射信息諸如返回類型參數類型和相關的 get/set 方法等這裡將不再贅述
關於緩存持久化以及日志等的策略後面我們將介紹一些這方面的信息
第二步指出了 ServerMBean 管理的對象也就是說從元數據中得到的 Method 將施加在哪個 Object 上需要指出的是 setManagedResource(Object o String type); 中第二個參數是 Object 類型可以是 ObjectReferenceHandleIOREJBHandle 或 RMIReference目前 SE 中的實現只支持 ObjectReference筆者認為後面幾種類型是為了將來 JMX 管理對象擴展而設定的可能將來 Model Bean 不僅可以管理 Plain Java Object(POJO)還可能管理 Native Resource 並給諸如 EJB 和 RMI 對象的管理提供更多的特性
Model Bean 與普通動態 Bean 區別在於它的元數據類型 ModelMBeanInfo 擴展了前者的 MBeanInfo使得 ModelMBeanOperationInfoModelMBeanConstructor_Info ModelMBeanAttributeInfo 和 ModelMBeanNotificationInfo 都有一個額外的元數據javaxmanagementDescriptor 它是用來設定 Model Bean 策略的數據的存儲是典型的 keyvalue 鍵值對不同的 Model Bean 實現以及不同的 MBeanFeatureInfo 支持不同的策略特性下面我們就以 Attribute 為例看一下 RequiredModelBean 支持的策略
首先它最重要的 Descriptor 主要是 namedisplayName 和 descriptorType其中 name 是屬性名稱name 要與對應 ModelMBeanAttributeInfo 的 name 相同descriptorType 必須是 attribute
另外valuedefault legalValues value 是用來設定初始值的default 指當不能從 resource 中獲得該屬性時的默認返回值legalValues 是一組合法的屬性數據它並不用來保證 setAttribute 的數據一致性而是在 UI 系統如 JConsole 中提示用戶可能的數據輸入
在屬性訪問的 getMethod setMethod 方法上事實上所有對屬性的訪問都會被 delegate 給同一 MBeanInfo 中特定的 Operation getMethod/setMethod 給出了對應的 ModelMBeanOperationInfo 名稱
還有一些額外的屬性比如persistPolicy persistPeriod 是代表了持久化策略currencyTimeLimit lastUpdatedTimeStamp 緩存策略iterable 屬性是否必須使用 iterate 來訪問默認為否protocolMap 定義了與第三方系統有關的數據轉換的 data modelvisibility 定義了與第三方 UI 系統有關的 MBean 如何顯示的策略presentationString 也是定義了與第三方 UI 系統有關的 MBean 如何顯示策略比如 presentation=servergif
事實上策略特性有兩個層次的作用域整個 Model Bean 和特定的 MBeanFeature
Model Bean 的策略描述會被施加到該 Model Bean 的所有 MBeanFeature 上去除非該 MBeanFeature 重寫了這個策略特性
在上面的例子裡這一個語句
serverMMBeanInfosetMBeanDescriptor(serverDescription);
給整個serverMBeanInfo 設了一個策略描述 serverDescription其中用 currencyTimeLimit= 指出屬性的緩存時間是 秒所以在 Main 方法中兩次 serverMBeangetAttribute(upTime)之間的間隔小於 秒就會得到同樣的緩存值
如果我們不想讓 upTime 這個屬性被緩存我們可以在它的策略描述中加入 currencyTimeLimit=:
Descriptor upTime = new DescriptorSupport(
new String[] {
name=upTime
descriptorType=attribute
displayName=Server upTime
getMethod=getUpTime
currencyTimeLimit= //不需要緩存
});
Descriptor getUpTimeDesc =
new DescriptorSupport(
new String[] {
name=getUpTime
descriptorType=operation
class=modelmbeanServer
role=operation
currencyTimeLimit= //不需要緩存
});
getUpTimeDesc 也要改動的原因是 RequiredModelBean 會把獲取 upTime 屬性的工作 delegate 給 getUpTime invocation只要其中一處使用 MBean 級的緩存策略就沒法獲得實時 upTime 數據了
虛擬機檢測
JMX 與虛擬機檢測
JMX 的提出為Java 虛擬機提供了 Java 層上的檢測機制JSE 中新提出的 javalangmanagement 包即是 JMX 在 JDK 的一個應用它提供了大量的有用的接口通過 MBean 方式提供了對 Java 虛擬機和運行時遠端的監控和檢測方式來幫助用戶來檢測本地或者遠端的虛擬機的運行情況有了 JMX 之後我們可以設計一個客戶端來檢測遠端一個正在運行的虛擬機中的線程數線程當前的 Stack內存管理GC 所占用的時間虛擬機中的對象和當前虛擬機參數等重要的參數和運行時信息JMX 另外的一個重要功能是對配置信息的檢測和再配置比如我們可以在遠端查看和修改當前 JVM 的 verbose 參數以達到動態管理的目的甚至我們可以在遠端指揮 JVM 做一次 GC這在下文中有詳細介紹
JMX 提供的虛擬機檢測 API
檢測虛擬機當前的狀態總是 Java 開放人員所關心的也正是因為如此出現了大量的 profiler 工具來檢測當前的虛擬機狀態從 Java SE 之後在 JDK 中我們有了一些 Java 的虛擬機檢測 API即 javalangmanagement 包Management 包裡面包括了許多 MXBean 的接口類和 LockInfoMemoryUsageMonitorInfo 和 ThreadInfo 等類從名字可以看出該包提供了虛擬機內存分配垃圾收集(GC)情況操作系統層線程調度和共享鎖甚至編譯情況的檢測機制這樣一來Java 的開發人員就可以很簡單地為自己做一些輕量級的系統檢測來確定當前程序的各種狀態以便隨時調整
要獲得這些信息我們首先通過 javalangmanagementManagementFactory 這個工廠類來獲得一系列的 MXBean包括
ClassLoadingMXBean
ClassLoadMXBean 包括一些類的裝載信息比如有多少類已經裝載/卸載(unloaded)虛擬機類裝載的 verbose 選項(即命令行中的 Java –verbose:class 選項)是否打開還可以幫助用戶打開/關閉該選項
CompilationMXBean
CompilationMXBean 幫助用戶了解當前的編譯器和編譯情況該 mxbean 提供的信息不多
GarbageCollectorMXBean
相 對於開放人員對 GC 的關注程度來說該 mxbean 提供的信息十分有限僅僅提供了 GC 的次數和 GC 花費總時間的近似值但是這個包中還提供了三個的內存管理檢測類MemoryManagerMXBeanMemoryMXBean 和 MemoryPoolMXBean
MemoryManagerMXBean
這個類相對簡單提供了內存管理類和內存池(memory pool)的名字信息
MemoryMXBean
這個類提供了整個虛擬機中內存的使用情況包括 Java 堆(heap)和非 Java 堆所占用的內存提供當前等待 finalize 的對象數量它甚至可以做 gc(實際上是調用 Systemgc)
MemoryPoolMXBean
該 信息提供了大量的信息在 JVM 中可能有幾個內存池因此有對應的內存池信息因此在工廠類中getMemoryPoolMXBean() 得到是一個 MemoryPoolMXBean 的 list每一個 MemoryPoolMXBean 都包含了該內存池的詳細信息如是否可用當前已使用內存/最大使用內存值以及設置最大內存值等等
OperatingSystemMXBean
該類提供的是操作系統的簡單信息如構架名稱當前 CPU 數最近系統負載等
RuntimeMXBean
運行時信息包括當前虛擬機的名稱提供商版本號以及 classpathbootclasspath 和系統參數等等
ThreadMXBean
在 Java 這個多線程的系統中對線程的監控是相當重要的ThreadMXBean 就是起到這個作用ThreadMXBean 可以提供的信息包括各個線程的各種狀態CPU 占用情況以及整個系統中的線程狀況從 ThreadMXBean 可以得到某一個線程的 ThreadInfo 對象這個對象中則包含了這個線程的所有信息
javalangmanagement 和虛擬機的關系
我們知道management 和底層虛擬機的關系是非常緊密的其實有一些的是直接依靠虛擬機提供的公開 API 實現的比如 JVMTI而另外一些則不然很大一塊都是由虛擬機底層提供某些不公開的 API / Native Code 提供的這樣的設計方式保證了 management 包可以提供足夠的信息並且使這些信息的提供又有足夠的效率也使 management 包和底層的聯系非常緊密
Java 中的 API 改進
Management 在 Java SE 被提出之後受到了歡迎在 Java 當中這個包提供更多的 API 來更好地提供信息
OperatingSystemMXBean getSystemLoadAverage()
Java 程序通常關注是虛擬機內部的負載內存等狀況而不考慮整個系統的狀況但是很多情況下Java 程序在運行過程中整個計算機系統的系統負荷情況也會對虛擬機造成一定的影響隨著 Java 的發展Java 程序已經覆蓋了各個行業這一點也必須得到關注在以前利用 Native 代碼來檢測系統負載往往是唯一的選擇但是在 Java 當中JDK 自己提供了一個輕量級的系統負載檢測 API即 OperatingSystemMXBeangetSystemLoadAverage()
當然這個 API 事實上僅僅返回一個對前一分鐘系統負載的簡單的估測它設計的主要目標是簡單快速地估測當前系統負荷因此它首先保證了這個 API 的效率是非常高的也因為如此這個 API 事實上並不適用於所有的系統
鎖檢測
我們知道同步是 Java 語言很重要的一個特性在 Java SE 中最主要的同步機制是依靠 synchronize 關鍵字對某一個對象加鎖實現的在 Java SE 之後的版本中concurrent 包的加入大大強化了 Java 語言的同步能力concurrent 提供了很多不同類型的鎖機制可供擴展因此要更好地觀測當前的虛擬機狀況和不同線程的運行態去觀察虛擬機中的各種鎖以及線程與鎖的關系是非常必要 的很可惜的是在過去的 JDK 中我們並沒有非常方便的 API 以供使用一個比較直接的檢測方式是查看線程的 stack trace更為強大全面(但是也更復雜並且效率低下)的方案是得到一個 VM 所有對象的快照並查找之這些策略的代價都比較大而且往往需要編寫復雜的 Native 代碼
JDK 裡提供了一些相當簡單的 API 來提供這個服務首先了解兩個新類LockInfo 和 MonitorInfo 這兩個類承載了鎖的信息LockInfo 可以是任何的 Java 鎖包括簡單 Java 鎖和 ncurrent 包中所使用的鎖(包括 AbstractOwnableSynchronizer 和 Condition 的實現類/子類)而 MonitorInfo 是簡單的 Java 對象所代表的鎖要檢測一個線程所擁有的鎖和等待的鎖首先要得到一個線程的 ThreadInfo然後可以簡單地調用
getLockedMonitors()
返回一個所有當前線程已經掌握的鎖對象的列表
getLockedSynchronizers()
對於使用 concurrent 包的線程返回一個該線程所掌握的ownable synchronizer(即 AbstractOwnableSynchronizer 及其子類)所組成的列表
getLockInfo()
當前線程正在等待的那個鎖對象的信息就可以知道線程所有的鎖信息通過這些鎖信息我們很方便的可以知道當前虛擬機的所有線程的鎖信息由此我們還可以推導出更多的信息
死鎖檢測
死鎖檢測一直以來是軟件工程師所重視的顯然一個死鎖的系統永遠是工程師最大的夢魇Java 程序的死鎖檢測也一直以來是 Java 程序員所頭痛的為了解決線程間死鎖問題一般都有預防(代碼實現階段)和死鎖後恢復(運行時)兩種方式以前 Java 程序員都重視前者因為在運行態再來檢測和恢復系統是相當麻煩的缺少許多必要的信息但是對於一些比較復雜的系統采取後者或者運行時調試死鎖信息也 是非常重要的由上面所說現在我們已經可以知道每一個線程所擁有和等待的鎖因此要計算出當前系統中是否有死鎖的線程也是可行的了當然Java 裡面也提供了一個 API 來完成這個功能即
ThreadMXBean
findDeadlockedThreads()
這個函數的功能就是檢測出當前系統中已經死鎖的線程當然這個功能復雜因此比較費時基本上僅僅將之用於調試以便對復雜系統線程調用的改進
未來的發展
JMX 在 Java SE / 中的功能已經相當強大但是距離 Java 程序開發人員的要求還是有一段距離因此 Sun 公司已經向 JCP 提出了 JSR (JMX API 版本)來擴充和進一步發展 JMX並希望這個 JSR 將在 Java SE 中實現在這個文檔中新的 JMX 將著重於
對 management 模型的優化
並提供更好的支持
加入了比如 annotation 等等的新特性
對 JMX 定義的優化
在進一步強化 MBean 擴充性好的優點的同時
盡量改變(用戶普遍認為的)MBean 很難實現的缺點
對非 Java 平台客戶端的支持
這將是一個令人振奮的新特性
具體的擴展可能包括
層次性的命名域(Hierarchical namespace)
新的事件服務功能
對 locales 的新支持
為 MBean 啟用 annotation 服務
也可以使用用戶類型的 mapping 了
可以看到JMX 的進一步發展主要關注的是可擴展性動態性和易用性等 Java 用戶非常關注的方面
總結
在Java SE 出現的 JMX 在 Java SE 中有了更多的功能和擴展能力這很好地適應了 Java 語言的發展和用戶的要求讓 Java 的監測管理的的功能更加強大
From:http://tw.wingwit.com/Article/program/Java/Javascript/201311/8553.html