Use FastThreadLocal for skipFlagsCache
Related: #3113 Motivation: Because ChannelHandlerContext is most often instantiated by an I/O thread, we can rely on thread-local variables to keep the skipFlags cache, which should be faster than partitioned synchronized variable. Modifications: Use FastThreadLocal for skipFlagsCache instead of partitioned synchronized map. Result: Less contention
This commit is contained in:
parent
9465db25ba
commit
2183c129d1
|
@ -22,6 +22,7 @@ import io.netty.util.AttributeKey;
|
|||
import io.netty.util.ReferenceCountUtil;
|
||||
import io.netty.util.ResourceLeakHint;
|
||||
import io.netty.util.concurrent.EventExecutor;
|
||||
import io.netty.util.concurrent.FastThreadLocal;
|
||||
import io.netty.util.concurrent.PausableEventExecutor;
|
||||
import io.netty.util.internal.OneTimeTask;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
@ -81,20 +82,20 @@ abstract class AbstractChannelHandlerContext implements ChannelHandlerContext, R
|
|||
MASK_FLUSH;
|
||||
|
||||
/**
|
||||
* Cache the result of the costly generation of {@link #skipFlags} in the partitioned synchronized
|
||||
* {@link WeakHashMap}.
|
||||
* Cache the result of the costly generation of {@link #skipFlags} in a thread-local {@link WeakHashMap}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final WeakHashMap<Class<?>, Integer>[] skipFlagsCache =
|
||||
new WeakHashMap[Runtime.getRuntime().availableProcessors()];
|
||||
private static final FastThreadLocal<WeakHashMap<Class<?>, Integer>> skipFlagsCache =
|
||||
new FastThreadLocal<WeakHashMap<Class<?>, Integer>>() {
|
||||
@Override
|
||||
protected WeakHashMap<Class<?>, Integer> initialValue() throws Exception {
|
||||
return new WeakHashMap<Class<?>, Integer>();
|
||||
}
|
||||
};
|
||||
|
||||
private static final AtomicReferenceFieldUpdater<AbstractChannelHandlerContext, PausableChannelEventExecutor>
|
||||
WRAPPED_EVENTEXECUTOR_UPDATER;
|
||||
|
||||
static {
|
||||
for (int i = 0; i < skipFlagsCache.length; i ++) {
|
||||
skipFlagsCache[i] = new WeakHashMap<Class<?>, Integer>();
|
||||
}
|
||||
AtomicReferenceFieldUpdater<AbstractChannelHandlerContext, PausableChannelEventExecutor> updater =
|
||||
PlatformDependent.newAtomicReferenceFieldUpdater(
|
||||
AbstractChannelHandlerContext.class, "wrappedEventLoop");
|
||||
|
@ -111,18 +112,15 @@ abstract class AbstractChannelHandlerContext implements ChannelHandlerContext, R
|
|||
* Otherwise, it delegates to {@link #skipFlags0(Class)} to get it.
|
||||
*/
|
||||
static int skipFlags(ChannelHandler handler) {
|
||||
WeakHashMap<Class<?>, Integer> cache =
|
||||
skipFlagsCache[(int) (Thread.currentThread().getId() % skipFlagsCache.length)];
|
||||
WeakHashMap<Class<?>, Integer> cache = skipFlagsCache.get();
|
||||
Class<? extends ChannelHandler> handlerType = handler.getClass();
|
||||
int flagsVal;
|
||||
synchronized (cache) {
|
||||
Integer flags = cache.get(handlerType);
|
||||
if (flags != null) {
|
||||
flagsVal = flags;
|
||||
} else {
|
||||
flagsVal = skipFlags0(handlerType);
|
||||
cache.put(handlerType, Integer.valueOf(flagsVal));
|
||||
}
|
||||
Integer flags = cache.get(handlerType);
|
||||
if (flags != null) {
|
||||
flagsVal = flags;
|
||||
} else {
|
||||
flagsVal = skipFlags0(handlerType);
|
||||
cache.put(handlerType, Integer.valueOf(flagsVal));
|
||||
}
|
||||
|
||||
return flagsVal;
|
||||
|
@ -236,6 +234,7 @@ abstract class AbstractChannelHandlerContext implements ChannelHandlerContext, R
|
|||
/**
|
||||
* Wrapped {@link EventLoop} and {@link ChannelHandlerInvoker} to support {@link Channel#deregister()}.
|
||||
*/
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private volatile PausableChannelEventExecutor wrappedEventLoop;
|
||||
|
||||
AbstractChannelHandlerContext(
|
||||
|
|
Loading…
Reference in New Issue
Block a user