美文网首页
第26周——ThreadLocal详解

第26周——ThreadLocal详解

作者: 阳光的nick_lxz | 来源:发表于2018-07-25 11:26 被阅读0次

一 什么是ThreadLocal

ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定线程(哪里存的哪里才能取到)才可以获取到存在的数据,说白了,它的作用域就是线程,你现在线程A中存储了值,只能在线程A中取得到。
eg:在thread1中存入数据,只有在thread1中才能取到这个数据,在thread2等其他线程获取不到该数据。

public class Main2Activity extends AppCompatActivity {
    private static final String TAG = "Main2Activity";
    ThreadLocal<String> threadLocal;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        threadLocal = new ThreadLocal<>();
        threadLocal.set("主线程");

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                threadLocal.set("存储数据");
                Log.e(TAG, "run: " + threadLocal.get());
            }
        });
        thread.start();
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                Log.e(TAG, "run: " + threadLocal.get());
            }
        });
        thread2.start();
        Log.e(TAG, "run: " + threadLocal.get());
    }

}

打印结果

07-24 17:20:56.294 8091-8091/? E/Main2Activity: run: 主线程
07-24 17:20:56.294 8091-8104/? E/Main2Activity: run: 存储数据
07-24 17:20:56.295 8091-8105/? E/Main2Activity: run: null

通过上面的例子我们发现,明明用的是一个全局的变量threadLocal,但是3条日志内容却不一样。这就是threadLocal精华所在了。

二源码解析

先看set和get方法

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);
    }

可以看到,先拿到当前线程,,,,注意是当前线程(就是调用方法时候所在的线程),然后通过该线程拿到ThreadLocalMap 这个对象。。。它是个ThreadLocal的静态内部类。
源码注释是这样的

    /**
     * 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.
     */

就是本地线程存储数据的一个类,然后用这个对象去set值,key传的是当前线程,value就是内容了。
我们在进一步深入点进去map.set()方法

       /**
         * Set the value associated with key.
         *
         * @param key the thread local object
         * @param value the value to be set
         */
        private void set(ThreadLocal<?> key, Object value) {

            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();

                if (k == key) {
                    e.value = value;
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

这里涉及到的算法就不管了,如果得到的K是就当前ThreadLocal对象,就赋值。

    if (k == key) {
                    e.value = value;
                    return;
                }

get方法

    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();
    }

这个更明了了,得到当前线程,获取ThreadLocalMap对象,然后在获取ThreadLocalMap.Entry 取值。如果ThreadLocalMap为空则会返回空,setInitialValue()方法默认返回空的。

总结

ThreadLocal是一个线程本地变量,一个作用域在线程的变量,不同的线程设置和修改的ThreadLocal值互不影响
原理:ThreadLocal在get值和set值的时候都会先获取当前线程的ThreadLocalMap对象,ThreadLocalMap把ThreadLocal作为key来取值或者存值(相当于每个线程都有个ThreadLocal对象),这样对于每一个线程所存储的数据都是基于线程的,互不相干。

相关文章

  • ThreadLocal和InheritableThreadLoc

    ThreadLocal详解 - 简书 InheritableThreadLocal详解 - 简书 ThreadLo...

  • InheritableThreadLocal详解

    1、简介 在上一篇 ThreadLocal详解 中,我们详细介绍了ThreadLocal原理及设计,从源码层面上分...

  • ThreadLocal 详解

    ThreadLocal 详解 1. 前言 ThreadLocal是java线程中的局部变量,变量作用域仅在当前线程...

  • 第26周——ThreadLocal详解

    一 什么是ThreadLocal ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数...

  • ThreadLocal详解

    1、简介 ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Th...

  • ThreadLocal详解

    ThreadLocal之前我认为就是内部维护了一个ThreadLocalMap其中key为当前线程(Thread....

  • ThreadLocal详解

    介绍 顾名思义这个类提供线程局部变量每个线程(通过其get或set方法)都有自己独立初始化的变量副本 Thread...

  • ThreadLocal 详解

    ThreadLocal,我们一般称之为线程的局部变量,或者是线程的本地变量。很多人认为他与多线程的同步机制相关,其...

  • ThreadLocal详解

    ThreadLocal在java.lang包中,其主要作用是提供一个和线程绑定的变量环境,即通过ThreadLoc...

  • ThreadLocal详解

    ThreadLocal说明 ThreadLocal是一个线程内部的数据存储类,使用它来保存数据,只有当前的线程才可...

网友评论

      本文标题:第26周——ThreadLocal详解

      本文链接:https://www.haomeiwen.com/subject/iarymftx.html