Skip to content

Commit 787b0c2

Browse files
committed
Optimize InternalTimerHandler disposed state handling
Motivation: InternalTimerHandler used AtomicBoolean for disposal tracking, which adds an object allocation and extra indirection in a hot timer path. Changes: - Replaced the per-instance AtomicBoolean disposed field with a volatile boolean field. - Added a static VarHandle for InternalTimerHandler.disposed and a disposedCAS helper to preserve atomic compare-and-set behavior where required. - Kept periodic timer execution checks as volatile reads while retaining one-shot/cancel atomicity. Results: mvn -pl vertx-core -DskipTests compile passes.
1 parent 2e588f2 commit 787b0c2

1 file changed

Lines changed: 20 additions & 5 deletions

File tree

vertx-core/src/main/java/io/vertx/core/impl/VertxImpl.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,15 @@
7373

7474
import java.io.IOException;
7575
import java.io.InputStream;
76+
import java.lang.invoke.MethodHandles;
77+
import java.lang.invoke.VarHandle;
7678
import java.lang.ref.Cleaner;
7779
import java.lang.ref.WeakReference;
7880
import java.lang.reflect.Method;
7981
import java.net.InetSocketAddress;
8082
import java.nio.charset.StandardCharsets;
8183
import java.util.*;
8284
import java.util.concurrent.*;
83-
import java.util.concurrent.atomic.AtomicBoolean;
8485
import java.util.concurrent.atomic.AtomicInteger;
8586
import java.util.concurrent.atomic.AtomicLong;
8687
import java.util.function.Function;
@@ -107,12 +108,26 @@ public class VertxImpl implements VertxInternal, MetricsProvider {
107108
// https://github.com/eclipse-vertx/vert.x/issues/4611
108109

109110
private static final Logger log = LoggerFactory.getLogger(VertxImpl.class);
111+
private static final VarHandle INTERNAL_TIMER_HANDLER_DISPOSED;
112+
113+
static {
114+
try {
115+
INTERNAL_TIMER_HANDLER_DISPOSED = MethodHandles.lookup()
116+
.findVarHandle(InternalTimerHandler.class, "disposed", boolean.class);
117+
} catch (NoSuchFieldException | IllegalAccessException e) {
118+
throw new IllegalArgumentException(e);
119+
}
120+
}
110121

111122
static final Object[] EMPTY_CONTEXT_LOCALS = new Object[0];
112123
private static final String CLUSTER_MAP_NAME = "__vertx.haInfo";
113124
private static final String NETTY_IO_RATIO_PROPERTY_NAME = "vertx.nettyIORatio";
114125
private static final int NETTY_IO_RATIO = Integer.getInteger(NETTY_IO_RATIO_PROPERTY_NAME, 50);
115126

127+
private static boolean disposedCAS(InternalTimerHandler handler) {
128+
return INTERNAL_TIMER_HANDLER_DISPOSED.compareAndSet(handler, false, true);
129+
}
130+
116131
// Not cached for graalvm
117132
private static ThreadFactory virtualThreadFactory() {
118133
try {
@@ -1063,7 +1078,7 @@ class InternalTimerHandler implements Handler<Void>, Closeable, Runnable {
10631078
private final boolean periodic;
10641079
private final long id;
10651080
private final ContextInternal context;
1066-
private final AtomicBoolean disposed = new AtomicBoolean();
1081+
private volatile boolean disposed;
10671082
private volatile java.util.concurrent.Future<?> future;
10681083

10691084
InternalTimerHandler(long id, Handler<Long> runnable, boolean periodic, ContextInternal context) {
@@ -1084,10 +1099,10 @@ public void run() {
10841099

10851100
public void handle(Void v) {
10861101
if (periodic) {
1087-
if (!disposed.get()) {
1102+
if (!disposed) {
10881103
handler.handle(id);
10891104
}
1090-
} else if (disposed.compareAndSet(false, true)) {
1105+
} else if (disposedCAS(this)) {
10911106
timeouts.remove(id);
10921107
try {
10931108
handler.handle(id);
@@ -1109,7 +1124,7 @@ private boolean cancel() {
11091124
}
11101125

11111126
private boolean tryCancel() {
1112-
if (disposed.compareAndSet(false, true)) {
1127+
if (disposedCAS(this)) {
11131128
timeouts.remove(id);
11141129
future.cancel(false);
11151130
return true;

0 commit comments

Comments
 (0)