From 05480c190f19630322ea8d26f5f51b27a7efd077 Mon Sep 17 00:00:00 2001 From: Carl Mastrangelo Date: Wed, 23 Oct 2019 23:35:11 -0700 Subject: [PATCH] Make only default IdleStateEvents cached string representation (#9705) Motivation: In PR https://github.com/netty/netty/pull/9695 IdleStateEvents were made to cache their string representation. The reason for this was to avoid creating garbage as these values would be used frequently. However, these objects may be used on multiple event loops and this may cause an unexpected race to occur. Modification: Only make the events that Netty creates cache their toString representation. Result: No races. --- .../netty/handler/timeout/IdleStateEvent.java | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/handler/src/main/java/io/netty/handler/timeout/IdleStateEvent.java b/handler/src/main/java/io/netty/handler/timeout/IdleStateEvent.java index 6617daa834..1a89798c78 100644 --- a/handler/src/main/java/io/netty/handler/timeout/IdleStateEvent.java +++ b/handler/src/main/java/io/netty/handler/timeout/IdleStateEvent.java @@ -25,16 +25,21 @@ import io.netty.util.internal.StringUtil; * A user event triggered by {@link IdleStateHandler} when a {@link Channel} is idle. */ public class IdleStateEvent { - public static final IdleStateEvent FIRST_READER_IDLE_STATE_EVENT = new IdleStateEvent(IdleState.READER_IDLE, true); - public static final IdleStateEvent READER_IDLE_STATE_EVENT = new IdleStateEvent(IdleState.READER_IDLE, false); - public static final IdleStateEvent FIRST_WRITER_IDLE_STATE_EVENT = new IdleStateEvent(IdleState.WRITER_IDLE, true); - public static final IdleStateEvent WRITER_IDLE_STATE_EVENT = new IdleStateEvent(IdleState.WRITER_IDLE, false); - public static final IdleStateEvent FIRST_ALL_IDLE_STATE_EVENT = new IdleStateEvent(IdleState.ALL_IDLE, true); - public static final IdleStateEvent ALL_IDLE_STATE_EVENT = new IdleStateEvent(IdleState.ALL_IDLE, false); + public static final IdleStateEvent FIRST_READER_IDLE_STATE_EVENT = + new DefaultIdleStateEvent(IdleState.READER_IDLE, true); + public static final IdleStateEvent READER_IDLE_STATE_EVENT = + new DefaultIdleStateEvent(IdleState.READER_IDLE, false); + public static final IdleStateEvent FIRST_WRITER_IDLE_STATE_EVENT = + new DefaultIdleStateEvent(IdleState.WRITER_IDLE, true); + public static final IdleStateEvent WRITER_IDLE_STATE_EVENT = + new DefaultIdleStateEvent(IdleState.WRITER_IDLE, false); + public static final IdleStateEvent FIRST_ALL_IDLE_STATE_EVENT = + new DefaultIdleStateEvent(IdleState.ALL_IDLE, true); + public static final IdleStateEvent ALL_IDLE_STATE_EVENT = + new DefaultIdleStateEvent(IdleState.ALL_IDLE, false); private final IdleState state; private final boolean first; - private String strVal; /** * Constructor for sub-classes. @@ -63,9 +68,20 @@ public class IdleStateEvent { @Override public String toString() { - if (strVal == null) { - strVal = StringUtil.simpleClassName(this) + "(" + state + (first ? ", first" : "") + ')'; + return StringUtil.simpleClassName(this) + '(' + state + (first ? ", first" : "") + ')'; + } + + private static final class DefaultIdleStateEvent extends IdleStateEvent { + private final String representation; + + DefaultIdleStateEvent(IdleState state, boolean first) { + super(state, first); + this.representation = "IdleStateEvent(" + state + (first ? ", first" : "") + ')'; + } + + @Override + public String toString() { + return representation; } - return strVal; } }