All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.dubbo.common.threadlocal.InternalThreadLocal Maven / Gradle / Ivy

There is a newer version: 3.3.0-beta.3
Show newest version
/*
 * Copyright 2014 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package org.apache.dubbo.common.threadlocal;

import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Set;

/**
 * InternalThreadLocal
 * A special variant of {@link ThreadLocal} that yields higher access performance when accessed from a
 * {@link InternalThread}.
 * 

* Internally, a {@link InternalThread} uses a constant index in an array, instead of using hash code and hash table, * to look for a variable. Although seemingly very subtle, it yields slight performance advantage over using a hash * table, and it is useful when accessed frequently. *

* This design is learning from {@see io.netty.util.concurrent.FastThreadLocal} which is in Netty. */ public class InternalThreadLocal extends ThreadLocal { private static final int VARIABLES_TO_REMOVE_INDEX = InternalThreadLocalMap.nextVariableIndex(); private final int index; public InternalThreadLocal() { index = InternalThreadLocalMap.nextVariableIndex(); } /** * Removes all {@link InternalThreadLocal} variables bound to the current thread. This operation is useful when you * are in a container environment, and you don't want to leave the thread local variables in the threads you do not * manage. */ @SuppressWarnings("unchecked") public static void removeAll() { InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet(); if (threadLocalMap == null) { return; } try { Object v = threadLocalMap.indexedVariable(VARIABLES_TO_REMOVE_INDEX); if (v != null && v != InternalThreadLocalMap.UNSET) { Set> variablesToRemove = (Set>) v; InternalThreadLocal[] variablesToRemoveArray = variablesToRemove.toArray(new InternalThreadLocal[0]); for (InternalThreadLocal tlv : variablesToRemoveArray) { tlv.remove(threadLocalMap); } } } finally { InternalThreadLocalMap.remove(); } } /** * Returns the number of thread local variables bound to the current thread. */ public static int size() { InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet(); if (threadLocalMap == null) { return 0; } else { return threadLocalMap.size(); } } public static void destroy() { InternalThreadLocalMap.destroy(); } @SuppressWarnings("unchecked") private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, InternalThreadLocal variable) { Object v = threadLocalMap.indexedVariable(VARIABLES_TO_REMOVE_INDEX); Set> variablesToRemove; if (v == InternalThreadLocalMap.UNSET || v == null) { variablesToRemove = Collections.newSetFromMap(new IdentityHashMap, Boolean>()); threadLocalMap.setIndexedVariable(VARIABLES_TO_REMOVE_INDEX, variablesToRemove); } else { variablesToRemove = (Set>) v; } variablesToRemove.add(variable); } @SuppressWarnings("unchecked") private static void removeFromVariablesToRemove(InternalThreadLocalMap threadLocalMap, InternalThreadLocal variable) { Object v = threadLocalMap.indexedVariable(VARIABLES_TO_REMOVE_INDEX); if (v == InternalThreadLocalMap.UNSET || v == null) { return; } Set> variablesToRemove = (Set>) v; variablesToRemove.remove(variable); } /** * Returns the current value for the current thread */ @SuppressWarnings("unchecked") @Override public final V get() { InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get(); Object v = threadLocalMap.indexedVariable(index); if (v != InternalThreadLocalMap.UNSET) { return (V) v; } return initialize(threadLocalMap); } public final V getWithoutInitialize() { InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get(); Object v = threadLocalMap.indexedVariable(index); if (v != InternalThreadLocalMap.UNSET) { return (V) v; } return null; } private V initialize(InternalThreadLocalMap threadLocalMap) { V v = null; try { v = initialValue(); } catch (Exception e) { throw new RuntimeException(e); } threadLocalMap.setIndexedVariable(index, v); addToVariablesToRemove(threadLocalMap, this); return v; } /** * Sets the value for the current thread. */ @Override public final void set(V value) { if (value == null || value == InternalThreadLocalMap.UNSET) { remove(); } else { InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get(); if (threadLocalMap.setIndexedVariable(index, value)) { addToVariablesToRemove(threadLocalMap, this); } } } /** * Sets the value to uninitialized; a proceeding call to get() will trigger a call to initialValue(). */ @SuppressWarnings("unchecked") @Override public final void remove() { remove(InternalThreadLocalMap.getIfSet()); } /** * Sets the value to uninitialized for the specified thread local map; * a proceeding call to get() will trigger a call to initialValue(). * The specified thread local map must be for the current thread. */ @SuppressWarnings("unchecked") public final void remove(InternalThreadLocalMap threadLocalMap) { if (threadLocalMap == null) { return; } Object v = threadLocalMap.removeIndexedVariable(index); removeFromVariablesToRemove(threadLocalMap, this); if (v != InternalThreadLocalMap.UNSET) { try { onRemoval((V) v); } catch (Exception e) { throw new RuntimeException(e); } } } /** * Returns the initial value for this thread-local variable. */ @Override protected V initialValue() { return null; } /** * Invoked when this thread local variable is removed by {@link #remove()}. */ protected void onRemoval(@SuppressWarnings("unused") V value) throws Exception { } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy