ThreadLocal

I came across the ThreadLocal class while blogging recently and looked it up.

ThreadLocal is a class that defines a ThreadLocaMap inner class. This inner class has characteristics that make it possible for each thread to call threadlocal.set (), threadlocal.get () and store or retrieve objects that belong to that thread. Thus ensuring security. So how did he do it?

ThreadLocal.set()

Let’s start with threadlocal.set ()

 /**
     * 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. * * @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);
    }
Copy the code

If the map does not exist, createMap will store this as a key and this as the threadLocal object itself. However, threadLocalMap does a good job of eliminating this problem, using threadLocalmap.remove.

/**
     * 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;
    }
Copy the code
void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
Copy the code

ThreadLocal.get()

Look again at the threadlocal.get () method

/**
     * 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. * * @return the current thread's value of this thread-local
     */
    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;
                returnresult; }}return setInitialValue();
    }
Copy the code

If the map exists, the value is obtained by this key. This object is not changed during this process, so the security of the object is guaranteed to be unique.

Of course, the first time the get() method is called, the map is empty, setInitialValue() is called,

    /**
     * Variant of set() to establish initialValue. Used instead
     * of set(a)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;
    }
    
    
    protected T initialValue() {
        return null;
    }
Copy the code

A map is initialized with a null value. If the set() method had been called before, it would not have been called.

ThreadLocalMap

ThreadLocalMap is the inner class defined in a ThreadLocal that is key to how ThreadLocal works.

/** * Construct a new map including all Inheritable ThreadLocals * from given parent map. Called only by createInheritedMap. * * @param parentMap the map associated with parent thread. */ private ThreadLocalMap(ThreadLocalMap  parentMap) { Entry[] parentTable = parentMap.table; int len = parentTable.length;setThreshold(len);
            table = new Entry[len];

            for (int j = 0; j < len; j++) {
                Entry e = parentTable[j];
                if(e ! = null) { @SuppressWarnings("unchecked")
                    ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
                    if(key ! = null) { Object value = key.childValue(e.value); Entry c = new Entry(key, value); int h = key.threadLocalHashCode & (len - 1);while(table[h] ! = null) h = nextIndex(h, len); table[h] = c; size++; }}}}Copy the code

But his real reference is in the Thread class.

/* ThreadLocal values pertaining to this thread. This map is maintained by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;
Copy the code

In the threadlocal.get () method you can see that the data type retrieved is Entry:

if(map ! = null) { ThreadLocalMap.Entry e = map.getEntry(this);Copy the code

Entry definitions for storing data in ThreadLocalMap:

static class Entry extends WeakReference<ThreadLocal<? >> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<? > k, Object v) { super(k); value = v; }}Copy the code

You can also see that the type of the stored key is ThreadLocal.

conclusion

At this point, we can understand how ThreadLocal works

1. The Thread class has a member variable that belongs to the ThreadLocalMap class (an inner class defined in the ThreadLocal class). It is a Map whose key is the ThreadLocal instance object.

2. If the value of a ThreadLocal object is set, the ThreadLocalMap class of the current thread is first obtained, and then the value of the ThreadLocal object is set as the key. It is similar for get values.

3. A ThreadLocal variable is owned by a thread, and all operations on the variable are performed by that thread. That is, ThreadLocal is not designed to solve the problem of competing for multithreaded access to shared objects, because objects in threadlocal.set () are objects that are used by the thread itself and not needed or accessible by other threads. These values are collected as garbage when the thread terminates.

Here’s an example:

private static final ThreadLocal threadSession = new ThreadLocal();  
  
public static Session getSession() throws InfrastructureException {  
    Session s = (Session) threadSession.get();  
    try {  
        if (s == null) {  
            s = getSessionFactory().openSession();  
            threadSession.set(s);  
        }  
    } catch (HibernateException ex) {  
        throw new InfrastructureException(ex);  
    }  
    return s;  
}
Copy the code

Refer to the article: www.cnblogs.com/xzwblog/p/7… www.cnblogs.com/since1499/p…