【Java/Android】ThreadLocal

作者: littlefogcat | 来源:发表于2021-02-01 15:48 被阅读0次

    一、ThreadLocal

    一个类可以通过 ThreadLocal 在当前线程内部创建一个独一无二的副本。通过threadLocal.get()threadLocal.set(inst)可以获取和设置当前线程中这个副本。
    换句话说,一个ThreadLocal<T>对象可以实现不同的线程对应不同的T类型对象。

    如下例:

            ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
            threadLocal.set(1);
            new Thread(() -> {
                threadLocal.set(2);
                System.out.println(threadLocal.get());
            }).start();
            Thread.sleep(10);
            System.out.println(threadLocal.get());
    

    以上代码打印结果为:

    2
    1

    ThreadLocal<T>有两个公开方法,get()set(T)

    • ThreadLocal.get()
        public T get() {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null) {
                ThreadLocalMap.Entry e = map.getEntry(this);
                if (e != null) {
                    T result = (T)e.value;
                    return result;
                }
            }
            return setInitialValue();
        }
    
    • ThreadLocal.set(T)
        public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
    
    • ThreadLocal.getMap(Thread)
        ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;
        }
    

    可以看到,ThreadLocal的原理其实很简单:在每个线程Thread中,都有一个ThreadLocal.ThreadLocalMap类型的变量;这是一个以ThreadLocal<T>对象为key,以对应的T类型对象为value的map。也就是说,当使用ThreadLocal.set(T)保存对象时,实际上存储的地方是线程的内部。

    虽然是在线程内部,key为ThreadLocal,value为T的map,但是也可以换个角度来看:
    每一个ThreadLocal对象,都相当于保存了一个以线程Thread为key,以对应类T的实例为value的map;而这个map是绝对线程安全的,并且规避了同步/加锁的开销。

    要注意这是一个ThreadLocal对象。如果创建了多个ThreadLocal对象,那么每个对象对应的值可以是不同的。

        ThreadLocal<Integer> t1 = new ThreadLocal<>();
        ThreadLocal<Integer> t2 = new ThreadLocal<>();
        t1.set(1);
        t2.set(2);
        System.out.println(t1.get() + ", " + t2.get());
    

    输出
    1, 2

    二、Android中的ThreadLocal与Looper

    在Android中,之所以能够实现每个线程对应一个Looper对象,其原理的就是使用了ThreadLocal。
    在Looper中,有一个静态成员sThreadLocal

        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    

    看Looper的prepare()myLooper()方法:

        private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(quitAllowed));
        }
        public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
    

    就是ThreadLocal的赋值与获取过程。

    相关文章

      网友评论

        本文标题:【Java/Android】ThreadLocal

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