Analyzed the interviewer beating and hanging series of Java source code base of ThreadLocal

In fact, ThreadLocal name is not very good, it should be renamed is called thread-local variable, namely thread-local variables. A ThreadLocal instance is a thread local variable. It features that can be accessed at any time through this ThreadLocal instance variable to the value of the bound (actually a bit about) the same thread; Note that the init method, which by default does not do anything, we usually need to override it, of course, this is entirely in accordance with the need to set. Every time you get a thread of execution, if found to its internal map has not been created, then create and call init initialization;

---- update, this statement is not quite accurate, although ThreadLocalMap static inner class ThreadLocal, but will not have to create a ThreadLocalMap each ThreadLocal, ThreadLocal but the entire jvm all share a ThreadLocalMap ~!

Kick the tires easily, in layman's language is difficult. Many times as long as the interviewer ask a few that he will fall into a state of senseless force; not understand, but there are always some places indistinct ~ .. no clearly very plainly, did not dare utter, simply fool about it; but it will be the interviewer himself away. It still needs careful study some source.


Source Analysis roughly
1 I thought before ThreadLocal to provide support for Thread, in fact, no, almost no relationship with Thread. In fact, the interior has a static ThreadLocal to ThreadLocalMap, this can be described as the most important; to understand it to understand ThreadLocal. ThreadLocalMap First, it is static, meaning that it only needs to be created throughout the jvm once! ~ ThreadLocalMap suggests that it is the ThreadLocal Map, but it is not internal field like a map, nor is it inherited the existing Map implementation HashMap and the like, it is their own re-implement the logic of the map; basically internal an array Entry [] table, key type is fixed ThreadLocal, value certainly is not fixed, static inner classes ThreadLocalMap.Entry, this Entry very special, inherited WeakReference <ThreadLocal <>>;? and expansion of the time, also every time * 2; and differential HashMap is still quite large; first here, there is no time to study thoroughly ..xxx (this is probably not the direct cause of HaspMap use of it)
after (WeakReference ensure the thread terminates, the corresponding thread variable i.e. ThreadLocal instance can be recovered ~!)

get Method 2 when in use, we directly call ThreadLocal instance of an object (such as tl) is, if it is the first time the whole jvm, then create ThreadLocalMap, then tl call getEntry (do not know why not get method, but to provide a getEntry method), the parameter is itself an object that is ThreadLocal instance tl, this strange, but also can be appreciated, the method of calculating the hash value of the internal getEntry tl and the like, corresponding to find it in the map array and slot, then return; if tl set method calls are similar, the same as the inside hashMap, there is a hash value calculated by the key process. remove, too, need to be removed tl corresponding entry.

In other words, each instance of the object actually corresponds ThreadLocal an Entry ThreadLocalMap instance of the object, each operation ThreadLocal instance object is actually in operation this Entry ~!

 

Use scenario?
Is the need to bind some of the variables on the thread when useful; if a thread needs to perform a lot of operations, may be a lot of cross-domain method calls the class level, but may also be time-consuming long, then; somewhat similar global variables, but it is thread-safe.
Specifically, when many threads need to repeatedly use the same object, and the object needs to have the same initialization value when it is best to use ThreadLocal. The most common usage scenario is used to solve the ThreadLocal database connection, Session management.

 

ThreadLocal VS multi-threaded lock

At first glance, and some multi-threaded lock somewhat similar, but the difference is very large, use a completely different scene. It can be said, ThreadLocal provides a single-threaded environment, so it is thread-safe variable, it avoids the problem of multi-threaded thread-safe; get, set, remove when the course is no need to consider concurrency issues, because only the called in the current thread; ThreadLocal provide a copy of the variable for each thread, so that each thread at a time to visit is not the same object, thus isolating the data shared by multiple threads of data

package java.lang;
import java.lang.ref.*;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;

/**
 * This class provides thread-local variables.  These variables differ from
 * their normal counterparts in that each thread that accesses one (via its
 * {@code get} or {@code set} method) has its own, independently initialized
 * copy of the variable.  {@code ThreadLocal} instances are typically private
 * static fields in classes that wish to associate state with a thread (e.g.,
 * a user ID or Transaction ID).
 *
 * <p>For example, the class below generates unique identifiers local to each
 * thread.
 * A thread's id is assigned the first time it invokes {@code ThreadId.get()}
 * and remains unchanged on subsequent calls.
 
 This class provides thread-local variables. These variables correspond to ordinary different variables, each variable access thread (through which {@code get} or {@code set} method) has its own, independent of the initialization variable copy. {@Code ThreadLocal} class instance is generally desirable state associated with the thread private static fields (e.g., user ID or transaction ID). <P> For example, the following classes will be generated locally unique identifier for each thread. Thread id is allocated at the first call when {@code ThreadId.get ()}, and retained during subsequent calls.
 
 * <pre>
 * import java.util.concurrent.atomic.AtomicInteger;
 *
 * public class ThreadId {
 *     // Atomic integer containing the next thread ID to be assigned
 *     private static final AtomicInteger nextId = new AtomicInteger(0);
 *
 *     // Thread local variable containing each thread's ID
 *     private static final ThreadLocal&lt;Integer&gt; threadId =
 *         new ThreadLocal&lt;Integer&gt;() {
 *             &#64;Override protected Integer initialValue() {
 *                 return nextId.getAndIncrement();
 *         }
 *     };
 *
 *     // Returns the current thread's unique ID, assigning it if necessary
 *     public static int get() {
 *         return threadId.get();
 *     }
 * }
 * </pre>
 * <p>Each thread holds an implicit reference to its copy of a thread-local
 * variable as long as the thread is alive and the {@code ThreadLocal}
 * instance is accessible; after a thread goes away, all of its copies of
 * thread-local instances are subject to garbage collection (unless other
 * references to these copies exist).
 *
 * @author  Josh Bloch and Doug Lea
 * @since   1.2
 */
public class ThreadLocal<T> {
    /**
     * ThreadLocals rely on per-thread linear-probe hash maps attached
     * to each thread (Thread.threadLocals and
     * inheritableThreadLocals).  The ThreadLocal objects act as keys,
     * searched via threadLocalHashCode.  This is a custom hash code
     * (useful only within ThreadLocalMaps) that eliminates collisions
     * in the common case where consecutively constructed ThreadLocals
     * are used by the same threads, while remaining well-behaved in
     * less common cases.
     */
    private final int threadLocalHashCode = nextHashCode();

    /**
     * The next hash code to be given out. Updated atomically. Starts at
     * zero.
     */
    private static AtomicInteger nextHashCode =
        new AtomicInteger();

    /**
     * The difference between successively generated hash codes - turns
     * implicit sequential thread-local IDs into near-optimally spread
     * multiplicative hash values for power-of-two-sized tables.
     */
    private static final int HASH_INCREMENT = 0x61c88647;

    /**
     * Returns the next hash code.
     */
    private static int nextHashCode() {
        return nextHashCode.getAndAdd(HASH_INCREMENT);
    }

    /**
     * Returns the current thread's "initial value" for this
     * thread-local variable.  This method will be invoked the first
     * time a thread accesses the variable with the {@link #get}
     * method, unless the thread previously invoked the {@link #set}
     * method, in which case the {@code initialValue} method will not
     * be invoked for the thread.  Normally, this method is invoked at
     * most once per thread, but it may be invoked again in case of
     * subsequent invocations of {@link #remove} followed by {@link #get}.
     *
     * <p>This implementation simply returns {@code null}; if the
     * programmer desires thread-local variables to have an initial
     * value other than {@code null}, {@code ThreadLocal} must be
     * subclassed, and this method overridden.  Typically, an
     * anonymous inner class will be used.
     
     Returns the current "initial value" thread local variables. This method uses {@link #get} method is called when the first thread access the variable, unless you call the {@link #set} method before the thread, in this case, {@ code initialValue} method does not It will be called. Typically, this method is called at most once per thread, but in the case of subsequent calls {@link #remove} and {@link #get}, this method may be called again. <P> This implementation simply returns {@code null}; if the programmer is not desired initial value {@code null} thread-local variables, then must subclass {@code ThreadLocal}, and override this method. Under normal circumstances, we will use an anonymous inner class.
     
     *
     * @return the initial value for this thread-local
     */
    protected T initialValue() {
        return null;
    }

    /**
     * Creates a thread local variable. The initial value of the variable is
     * determined by invoking the {@code get} method on the {@code Supplier}.
     
 Create a thread local variables, the initial value of the variable by calling {@code Supplier} {@code get} method on the decision. The initial value of the variable by calling {@code get} method determining.
     
     *
     * @param <S> the type of the thread local's value
     * @param supplier the supplier to be used to determine the initial value
     * @return a new thread local variable
     * @throws NullPointerException if the specified supplier is null
     * @since 1.8
     */
     SuppliedThreadLocal also internal static final class:
    public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
        return new SuppliedThreadLocal<>(supplier);
    }

    /**
     * Creates a thread local variable.
     * @see #withInitial(java.util.function.Supplier)
     */
    public ThreadLocal() {
    }

    /**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     The return value copy of thread local variables in the current. If this variable has no value for the current thread, then it is first initialized to call {@link #initialValue} value returned by the method.
     
     *
     * @Return the current thread's value of the local value of this thread-local thread of the current thread
     */
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

    /**
     * Variant of set() to establish initialValue. Used instead
     * of set() in case user has overridden the set() method.
     *
     * @return the initial value
     */
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

    /**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     A copy of the local variables of the current thread to the specified value. Most subclasses need not override this method only need to rely {@link #initialValue} method to set the value of the thread local variables.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

    /**
     * Removes the current thread's value for this thread-local
     * variable.  If this thread-local variable is subsequently
     * {@linkplain #get read} by the current thread, its value will be
     * reinitialized by invoking its {@link #initialValue} method,
     * unless its value is {@linkplain #set set} by the current thread
     * in the interim.  This may result in multiple invocations of the
     * {@code initialValue} method in the current thread.
     
   Delete the value of the current thread to thread local variable. If the thread is then the current thread local variable {@linkplain #get read}, its value by calling its {@link #initialValue} reinitialization method, unless its value is the current thread {@linkplain #set set}. This may result in multiple calls in the current thread {@code initialValue} method.
   
     *
     * @since 1.5
     */
     public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

    /**
     * Get the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param  t the current thread
     * @return the map
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

    /**
     * Create the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the map
     */
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

    /**
     * Factory method to create map of inherited thread locals.
     * Designed to be called only from Thread constructor.
     *
     * @param  parentMap the map associated with parent thread
     * @return a map containing the parent's inheritable bindings
     */
    static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
        return new ThreadLocalMap(parentMap);
    }

    /**
     * Method childValue is visibly defined in subclass
     * InheritableThreadLocal, but is internally defined here for the
     * sake of providing createInheritedMap factory method without
     * needing to subclass the map class in InheritableThreadLocal.
     * This technique is preferable to the alternative of embedding
     * instanceof tests in methods.
     */
    T childValue(T parentValue) {
        throw new UnsupportedOperationException();
    }

    /**
     * An extension of ThreadLocal that obtains its initial value from
     * the specified {@code Supplier}.
     */
    static final class SuppliedThreadLocal<T> extends ThreadLocal<T> {

        private final Supplier<? extends T> supplier;

        SuppliedThreadLocal(Supplier<? extends T> supplier) {
            this.supplier = Objects.requireNonNull(supplier);
        }

        @Override
        protected T initialValue() {
            return supplier.get();
        }
    }

    /**
     * ThreadLocalMap is a customized hash map suitable only for
     * maintaining thread local values. No operations are exported
     * outside of the ThreadLocal class. The class is package private to
     * allow declaration of fields in class Thread.  To help deal with
     * very large and long-lived usages, the hash table entries use
     * WeakReferences for keys. However, since reference queues are not
     * used, stale entries are guaranteed to be removed only when
     * the table starts running out of space.
     
     
Hash map ThreadLocalMap is a custom, applies only to maintain thread-local value. In addition ThreadLocal class, no action is derived. Such a package private, allowing Thread class declared fields. To help deal with very large and prolonged use of hash table entries using WeakReferences as a key. However, since no reference queue, it is only when the table began to run out of space, the old entry will be guaranteed deleted.

     * / 
    Static  class ThreadLocalMap {static inner classes

        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         
          This entry in the hash map entry extends the WeakReference, using its primary key field as ref (always a ThreadLocal object). Note that the empty keys (ie entry.get () == null) means that the key is no longer referenced, so the entry can be deleted from the table. Such entries are referred to in the following code "stale entries."
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

        /**
         * The initial capacity -- MUST be a power of two.
         */
        private static final int INITIAL_CAPACITY = 16;

        /**
         * The table, resized as necessary.
         * table.length MUST always be a power of two.
         */
        private Entry[] table;

        /**
         * The number of entries in the table.
         */
        private int size = 0;

        /**
         * The next size value at which to resize.
         */
        private int threshold; // Default to 0

        /**
         * Set the resize threshold to maintain at worst a 2/3 load factor.
         */
        private void setThreshold(int len) {
            threshold = as * 2 / 3 ;
        }

        /**
         * Increment i modulo len.
         */
        private static int nextIndex(int i, int len) {
            return ((i + 1 < len) ? i + 1 : 0);
        }

        /**
         * Decrement i modulo len.
         */
        private static int prevIndex(int i, int len) {
            return ((i - 1 >= 0) ? i - 1 : len - 1);
        }

        /**
         * Construct a new map initially containing (firstKey, firstValue).
         * ThreadLocalMaps are constructed lazily, so we only create
         * one when we have at least one entry to put in it.
         */
        ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }

        /**
         * Get the entry associated with key.  This method
         * itself handles only the fast path: a direct hit of existing
         * key. It otherwise relays to getEntryAfterMiss.  This is
         * designed to maximize performance for direct hits, in part
         * by making this method readily inlinable.
         *
         * @param  key the thread local object
         * @return the entry associated with key, or null if no such
         */
        private Entry getEntry(ThreadLocal<?> key) {
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            if (e != null && e.get() == key)
                return e;
            else
                return getEntryAfterMiss(key, i, e);
        }

        ....
}

 


Reference:
https://blog.csdn.net/ityouknow/article/details/90709371
https://blog.csdn.net/liuhaiabc/article/details/78077529
https://www.cnblogs.com/yxysuanfa/p/ 7125761.html

 

Guess you like

Origin www.cnblogs.com/FlyAway2013/p/12664189.html