【发布时间】:2010-10-12 16:26:06
【问题描述】:
有没有办法在不使用 JNI 的情况下获取 Java 下的当前 cpu 负载?
【问题讨论】:
有没有办法在不使用 JNI 的情况下获取 Java 下的当前 cpu 负载?
【问题讨论】:
getSystemLoadAverage() 为您提供超过 1 分钟的时间(每秒刷新一次),并为整个操作系统提供此值。应该通过分别监控每个线程来完成更实时的概览。重要的是还要注意监视刷新间隔 - 您更频繁地检查值,在给定时刻更精确,如果您每毫秒执行一次,它通常是 0 或 100(或更多取决于有多少 CPU)。但是,如果我们允许时间范围(例如 1 秒),我们会得到这段时间的平均值,并且我们会得到更多信息量的结果。此外,需要注意的是,只有一个线程占用多个 CPU(内核)的可能性很小。
以下实现允许使用 3 种方法:
getUsageByThread(Thread t) - 指定线程的总负载
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.ThreadMXBean;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class MonitoringThread extends Thread {
private long refreshInterval;
private boolean stopped;
private Map<Long, ThreadTime> threadTimeMap = new HashMap<Long, ThreadTime>();
private ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
private OperatingSystemMXBean opBean = ManagementFactory.getOperatingSystemMXBean();
public MonitoringThread(long refreshInterval) {
this.refreshInterval = refreshInterval;
setName("MonitoringThread");
start();
}
@Override
public void run() {
while(!stopped) {
Set<Long> mappedIds;
synchronized (threadTimeMap) {
mappedIds = new HashSet<Long>(threadTimeMap.keySet());
}
long[] allThreadIds = threadBean.getAllThreadIds();
removeDeadThreads(mappedIds, allThreadIds);
mapNewThreads(allThreadIds);
Collection<ThreadTime> values;
synchronized (threadTimeMap) {
values = new HashSet<ThreadTime>(threadTimeMap.values());
}
for (ThreadTime threadTime : values) {
synchronized (threadTime) {
threadTime.setCurrent(threadBean.getThreadCpuTime(threadTime.getId()));
}
}
try {
Thread.sleep(refreshInterval);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
for (ThreadTime threadTime : values) {
synchronized (threadTime) {
threadTime.setLast(threadTime.getCurrent());
}
}
}
}
private void mapNewThreads(long[] allThreadIds) {
for (long id : allThreadIds) {
synchronized (threadTimeMap) {
if(!threadTimeMap.containsKey(id))
threadTimeMap.put(id, new ThreadTime(id));
}
}
}
private void removeDeadThreads(Set<Long> mappedIds, long[] allThreadIds) {
outer: for (long id1 : mappedIds) {
for (long id2 : allThreadIds) {
if(id1 == id2)
continue outer;
}
synchronized (threadTimeMap) {
threadTimeMap.remove(id1);
}
}
}
public void stopMonitor() {
this.stopped = true;
}
public double getTotalUsage() {
Collection<ThreadTime> values;
synchronized (threadTimeMap) {
values = new HashSet<ThreadTime>(threadTimeMap.values());
}
double usage = 0D;
for (ThreadTime threadTime : values) {
synchronized (threadTime) {
usage += (threadTime.getCurrent() - threadTime.getLast()) / (refreshInterval * 10000);
}
}
return usage;
}
public double getAvarageUsagePerCPU() {
return getTotalUsage() / opBean.getAvailableProcessors();
}
public double getUsageByThread(Thread t) {
ThreadTime info;
synchronized (threadTimeMap) {
info = threadTimeMap.get(t.getId());
}
double usage = 0D;
if(info != null) {
synchronized (info) {
usage = (info.getCurrent() - info.getLast()) / (refreshInterval * 10000);
}
}
return usage;
}
static class ThreadTime {
private long id;
private long last;
private long current;
public ThreadTime(long id) {
this.id = id;
}
public long getId() {
return id;
}
public long getLast() {
return last;
}
public void setLast(long last) {
this.last = last;
}
public long getCurrent() {
return current;
}
public void setCurrent(long current) {
this.current = current;
}
}
}
【讨论】:
如果您使用的是JRockit JVM,您可以使用JMAPI。它适用于 JDK 1.4、1.5 和 1.6。
System.out.println("Total CPU-usage:" + JVMFactory.getJVM().getMachine().getCPULoad());
System.out.println("Total JVM-load :" + JVMFactory.getJVM().getJVMLoad());
for(Iterator it = JVMFactory.getJVM().getMachine().getCPUs().iterator(); it.hasNext();)
{
CPU cpu = (CPU)it.next();
System.out.println("CPU Description: " + cpu.getDescription());
System.out.println("CPU Clock Frequency: " + cpu.getClockFrequency());
System.out.println("CPU Load: " + cpu.getLoad());
System.out.println();
}
【讨论】:
这确实涉及 JNI,但 Hyperic 有一个名为 Sigar 的 GPL 库,它为所有主要平台提供此信息,以及一堆其他依赖于操作系统的统计信息,如磁盘使用情况。它对我们很有用。
【讨论】:
【讨论】:
在 linux 上,您可以只读取文件 /proc/loadavg,其中前三个值表示负载平均值。对于 Windows,您可能必须坚持使用 JNI。
【讨论】: