Analysis of ThreadLocal

What is ThreadLocal

We know that when using multiple threads, sometimes shared variables, you need to synchronize data between threads so this variable is open, this concept can be called an open thread. But not all data needs to be synchronized at all times, each thread can have its own unique variables, no synchronization to the other thread, this concept can be called a thread closed. The ThreadLocal thread is closed one specific manifestation. In JDK1.2 version provides a java.lang.ThreadLocal class, we can be understood as local variables ThreadLocal thread, a thread-level variables.

The simple practice of ThreadLocal

demo code is as follows:

public class TestMain {
    public static void main(String[] args) throws Exception {
        ThreadLocal<String> value = new ThreadLocal<>();
        value.set("主线程");
        String threadLocal = value.get();
        System.out.println("执行线程一前主线程threadLocal值为:" + threadLocal);
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                String threadLocal = value.get();
                System.out.println("设置线程一threadLocal值前,值为:" + threadLocal);
                value.set("线程一");
                String threadLocal1 = value.get();
                System.out.println("设置线程一threadLocal值后,值为:" + threadLocal1);
            }
        });
        thread.start();
        thread.join();
        System.out.println("线程一运行完后,主线程threadLocal值为" + threadLocal);
    }
}

Results are as follows:
Here Insert Picture Description
you can see the value of ThreadLocal main thread has been the "main thread", the thread in front of a set value is not null, set it to "a thread", two threads ThreadLocal value independently of each other, their own way.

ThreadLocal source code analysis of the get () method

get () method Source:

 public T get() {
        //获取当前线程
        Thread t = Thread.currentThread();
        //以线程为参数获取ThreadLocalMap对象
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            //从map里拿到线程对应的ThreadLocalMap.Entry对象
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                //获取ThreadLocalMap.Entry对象里的value值
                T result = (T)e.value;
                //返回结果
                return result;
            }
        }
        //如果该线程的ThreadLocal值为空,则设置初始值返回
        return setInitialValue();
    }

ThreadLocalMap source category:

  static class ThreadLocalMap {
        //静态内部类Entry
        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;


        //Entry数组
        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 = len * 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);
        }

the getMap () Method Source:

//threadLocals变量是ThreadLocalMap类
ThreadLocal.ThreadLocalMap threadLocals = null;
//返回ThreadLocalMap对象
ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

getEntry () Method Source:

private Entry getEntry(ThreadLocal<?> key) {
            //通过threadLocalHashCode进行一个位运算(取模)得到索引i
            int i = key.threadLocalHashCode & (table.length - 1);
            //通过索引值获取Entry实例
            Entry e = table[i];
            //满足条件下返回Entry,否则走另一个分支
            if (e != null && e.get() == key)
                return e;
            else
                return getEntryAfterMiss(key, i, e);
        }

getEntryAfterMiss () Method Source:

  private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
        Entry[] tab = table;
        int len = tab.length;
        //Entry不为空时做的逻辑
        while (e != null) {
            ThreadLocal<?> k = e.get();
            if (k == key)
                return e;
            if (k == null)
                expungeStaleEntry(i);
            else
                i = nextIndex(i, len);
            e = tab[i];
        }
        //返回空值
        return null;
    }

setInitialValue () Method Source:

 private T setInitialValue() {
        //返回null
        T value = initialValue();
        //取得当前线程
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            //如果ThreadLocalMap对象不为空,则为当前ThreadLocal对象设置对应value值
            map.set(this, value);
        else
            //创建ThreadLocalMap为当前线程存储ThreadLocal的value值
            createMap(t, value);
        return value;
    }
    //初始化值为null
 protected T initialValue() {
        return null;
    }        

set () method Source:

private void set(ThreadLocal<?> key, Object value) {
            Entry[] tab = table;
            int len = tab.length;
            //通过threadLocalHashCode进行一个位运算(取模)得到索引i
            int i = key.threadLocalHashCode & (len-1);
            //满足括号里条件的设值逻辑
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();
                //如果入参的ThreadLocal实例key和k相等,则把入参的value值设置为这个Entry的value值
                if (k == key) {
                    e.value = value;
                    return;
                }
                //k为空逻辑
                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
            //以入参key和value为参数,创建新的Entry对象,赋值给下标为i的Entry对象
            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }
        

createMap Source:

void createMap(Thread t, T firstValue) {
        //创建当前线程的ThreadLocalMap对象实例threadLocals,并赋值
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

From the above source can know, ThreadLocal which has a static inner classes ThreadLocalMap, ThreadLocalMap class which maintains an Entry array, we get () method is to first get ThreadLocalMap object as a parameter to the current thread, and then to ThreadLocal as parameters threadLocalHashCode be a bit operation (modulo) obtained index i, then removed from the target value corresponding to the attribute of the object inside Entry array by an index i. And if there is no corresponding thread ThreadLocalMap, or ThreadLocalMap object does not correspond to the Entry object, it will enter the initialization method setInitialValue () method, which will be initialized in the value is empty, then determine ThreadLocalMap target current thread is empty, is not empty, the call set () method set the value is empty then call createMap methods set value (), but here we want to know is whether it is which ones sleeved valued logic, set the value of the initialization value is null value time, which would explain why the thread start calling get () method, the value obtained is a null.

to sum up

The same thing, I believe that a simple analysis of the get () method, we can have some understanding of some of the variables and methods of ThreadLocal class. So if the data is the thread for the scope and requirements of each thread has its own copy, similar sessions, etc., then we can choose to use ThreadLocal.

Published 136 original articles · won praise 108 · views 10000 +

Guess you like

Origin blog.csdn.net/weixin_38106322/article/details/104109398
Recommended