JvmPauseMonitor,此类建立一个简单的线程。在此线程中,在循环中运行sleep一段时间方法,如果sleep花费的时间比传递给sleep方法的时间长,就意味着JVM或者宿主机已经出现了停顿处理现象,可能会导致其它问题,如果这种停顿被监测出来,线程会打印一个消息。
/** * Class which sets up a simple thread which runs in a loop sleeping * for a short interval of time. If the sleep takes significantly longer * than its target time, it implies that the JVM or host machine has * paused processing, which may cause other problems. If such a pause is * detected, the thread logs a message. */
private static final Log LOG = LogFactory.getLog( JvmPauseMonitor.class); /** The target sleep time */ private static final long SLEEP_INTERVAL_MS = 500;//sleep的时间 /** log WARN if we detect a pause longer than this threshold */ private final long warnThresholdMs; //成员变量,警告时间,如果超时到此时间,则发出警告。 private static final String WARN_THRESHOLD_KEY = "jvm.pause.warn-threshold.ms"; // 设置警告时间的配置项 private static final long WARN_THRESHOLD_DEFAULT = 10000; //静态变量,默认警告时间,如果超时到此时间,则发出警告。 /** log INFO if we detect a pause longer than this threshold */ private final long infoThresholdMs; //打印提示时间 private static final String INFO_THRESHOLD_KEY = "jvm.pause.info-threshold.ms"; //设置提示时间的配置项 private static final long INFO_THRESHOLD_DEFAULT = 1000; //静态变量,默认提示时间,如果超时到此时间,则发出提示。 private long numGcWarnThresholdExceeded = 0; //超过告警阈值的次数 private long numGcInfoThresholdExceeded = 0; //超过提示阈值的次数 private long totalGcExtraSleepTime = 0;//总的GC导致的另外花费时间 private Thread monitorThread;//监控线程,就是在此线程中循环调用sleep,并且计算时间的。 private volatile boolean shouldRun = true;//是否应该运行。
private static class GcTimes { private GcTimes(GarbageCollectorMXBean gcBean) { gcCount = gcBean.getCollectionCount(); gcTimeMillis = gcBean.getCollectionTime(); } private GcTimes(long count, long time) { this.gcCount = count; this.gcTimeMillis = time; } private GcTimes subtract(GcTimes other) { return new GcTimes(this.gcCount - other.gcCount, this.gcTimeMillis - other.gcTimeMillis); } @Override public String toString() { return "count=" + gcCount + " time=" + gcTimeMillis + "ms"; } private long gcCount; private long gcTimeMillis; }
private class Monitor implements Runnable { @Override public void run() { Stopwatch sw = new Stopwatch(); Map<String, GcTimes> gcTimesBeforeSleep = getGcTimes(); while (shouldRun) { sw.reset().start(); try { Thread.sleep(SLEEP_INTERVAL_MS); } catch (InterruptedException ie) { return; } long extraSleepTime = sw.elapsedMillis() - SLEEP_INTERVAL_MS; Map<String, GcTimes> gcTimesAfterSleep = getGcTimes(); if (extraSleepTime > warnThresholdMs) { ++numGcWarnThresholdExceeded; LOG.warn(formatMessage( extraSleepTime, gcTimesAfterSleep, gcTimesBeforeSleep)); } else if (extraSleepTime > infoThresholdMs) { ++numGcInfoThresholdExceeded; LOG.info(formatMessage( extraSleepTime, gcTimesAfterSleep, gcTimesBeforeSleep)); } totalGcExtraSleepTime += extraSleepTime; gcTimesBeforeSleep = gcTimesAfterSleep; } } }