Skip to content

Commit 50ba16b

Browse files
authored
Handle when ThreadPerTaskExecutor.threadCount() is not available (#7045)
Closes gh-6726 Signed-off-by: Johnny Lim <izeye@naver.com>
1 parent 50d273b commit 50ba16b

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jvm/ExecutorServiceMetrics.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ public class ExecutorServiceMetrics implements MeterBinder {
7070

7171
private static final String CLASS_NAME_THREAD_PER_TASK_EXECUTOR = "java.util.concurrent.ThreadPerTaskExecutor";
7272

73+
private static final String METHOD_NAME_THREAD_PER_TASK_EXECUTOR_THREAD_COUNT = "threadCount";
74+
7375
@Nullable
7476
private static final MethodHandle METHOD_HANDLE_THREAD_COUNT_FROM_THREAD_PER_TASK_EXECUTOR = getMethodHandleForThreadCountFromThreadPerTaskExecutor();
7577

@@ -464,6 +466,12 @@ private void monitor(MeterRegistry registry, ForkJoinPool fj) {
464466
}
465467

466468
private void monitorThreadPerTaskExecutor(MeterRegistry registry, ExecutorService executorService) {
469+
if (METHOD_HANDLE_THREAD_COUNT_FROM_THREAD_PER_TASK_EXECUTOR == null) {
470+
log.warn("{}.{}() is not available. Try '--add-opens java.base/java.util.concurrent=ALL-UNNAMED'.",
471+
CLASS_NAME_THREAD_PER_TASK_EXECUTOR, METHOD_NAME_THREAD_PER_TASK_EXECUTOR_THREAD_COUNT);
472+
return;
473+
}
474+
467475
List<Meter> meters = asList(Gauge
468476
.builder(metricPrefix + "executor.active", executorService,
469477
ExecutorServiceMetrics::getThreadCountFromThreadPerTaskExecutor)
@@ -487,7 +495,7 @@ private static long getThreadCountFromThreadPerTaskExecutor(ExecutorService exec
487495
private static MethodHandle getMethodHandleForThreadCountFromThreadPerTaskExecutor() {
488496
try {
489497
Class<?> clazz = Class.forName(CLASS_NAME_THREAD_PER_TASK_EXECUTOR);
490-
Method method = clazz.getMethod("threadCount");
498+
Method method = clazz.getMethod(METHOD_NAME_THREAD_PER_TASK_EXECUTOR_THREAD_COUNT);
491499
method.setAccessible(true);
492500
return MethodHandles.lookup().unreflect(method);
493501
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2026 VMware, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.micrometer.core.instrument.binder.jvm;
17+
18+
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
19+
import org.junit.jupiter.api.Test;
20+
21+
import java.util.concurrent.ExecutorService;
22+
import java.util.concurrent.Executors;
23+
24+
import static org.assertj.core.api.Assertions.assertThat;
25+
26+
/**
27+
* Tests for {@link ExecutorServiceMetrics}.
28+
*
29+
* @author Tommy Ludwig
30+
* @author Johnny Lim
31+
*/
32+
class ExecutorServiceMetricsTests {
33+
34+
SimpleMeterRegistry registry = new SimpleMeterRegistry();
35+
36+
@Test
37+
void monitorWithExecutorsNewVirtualThreadPerTaskExecutorWillBeDisabledWhenReflectionIsNotEnabled() {
38+
ExecutorService unmonitored = Executors.newVirtualThreadPerTaskExecutor();
39+
assertThat(unmonitored.getClass().getName()).isEqualTo("java.util.concurrent.ThreadPerTaskExecutor");
40+
ExecutorService monitored = ExecutorServiceMetrics.monitor(registry, unmonitored, "test");
41+
monitored.execute(() -> {
42+
});
43+
assertThat(registry.find("executor.active").gauge()).isNull();
44+
}
45+
46+
}

0 commit comments

Comments
 (0)