diff --git a/metrics-jvm/src/main/java/com/codahale/metrics/jvm/ThreadStatesGaugeSet.java b/metrics-jvm/src/main/java/com/codahale/metrics/jvm/ThreadStatesGaugeSet.java index 9b796a7bd3..f2024de0b1 100644 --- a/metrics-jvm/src/main/java/com/codahale/metrics/jvm/ThreadStatesGaugeSet.java +++ b/metrics-jvm/src/main/java/com/codahale/metrics/jvm/ThreadStatesGaugeSet.java @@ -8,7 +8,8 @@ import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.util.Collections; -import java.util.HashMap; +import java.util.EnumMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; @@ -21,6 +22,7 @@ public class ThreadStatesGaugeSet implements MetricSet { // do not compute stack traces. private final static int STACK_TRACE_DEPTH = 0; + private final static int[] ZERO_COUNT = new int[1]; private final ThreadMXBean threads; private final ThreadDeadlockDetector deadlockDetector; @@ -46,34 +48,35 @@ public ThreadStatesGaugeSet(ThreadMXBean threads, @Override public Map getMetrics() { - final Map gauges = new HashMap<>(); + final Map gauges = new LinkedHashMap<>(); // deterministic order + + // expensive methods only once, whether or not "cached" + ThreadInfo[] threadInfos = getThreadInfo(); + Set deadlockedThreads = deadlockDetector.getDeadlockedThreads(); + + EnumMap byState = new EnumMap<>(Thread.State.class); + for (ThreadInfo threadInfo : threadInfos) { + Thread.State tState; + if (threadInfo != null && (tState = threadInfo.getThreadState()) != null) { + byState.computeIfAbsent(tState, (k) -> new int[1])[0]++; + } + } for (final Thread.State state : Thread.State.values()) { gauges.put(name(state.toString().toLowerCase(), "count"), - (Gauge) () -> getThreadCount(state)); + (Gauge) () -> byState.getOrDefault(state, ZERO_COUNT)[0]); } gauges.put("count", (Gauge) threads::getThreadCount); gauges.put("daemon.count", (Gauge) threads::getDaemonThreadCount); gauges.put("peak.count", (Gauge) threads::getPeakThreadCount); gauges.put("total_started.count", (Gauge) threads::getTotalStartedThreadCount); - gauges.put("deadlock.count", (Gauge) () -> deadlockDetector.getDeadlockedThreads().size()); - gauges.put("deadlocks", (Gauge>) deadlockDetector::getDeadlockedThreads); + gauges.put("deadlock.count", (Gauge) deadlockedThreads::size); + gauges.put("deadlocks", (Gauge>) () -> deadlockedThreads); return Collections.unmodifiableMap(gauges); } - private int getThreadCount(Thread.State state) { - final ThreadInfo[] allThreads = getThreadInfo(); - int count = 0; - for (ThreadInfo info : allThreads) { - if (info != null && info.getThreadState() == state) { - count++; - } - } - return count; - } - ThreadInfo[] getThreadInfo() { return threads.getThreadInfo(threads.getAllThreadIds(), STACK_TRACE_DEPTH); }