ThreadLocal 学习笔记

在看Looper的源码时,发现有这么个sThreadLocal属性,研究了下

ThreadLocal官方的定义如下

Each thread holds an implicit reference to its copy of a thread-local
variable as long as the thread is alive and the 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).

大概意思就是每个线程都隐式持有这个本地变量副本,
我这么理解的,针对一个变量N,复制出两个副本NA和NB
分别给线程A和B去操作,彼此互不影响。

插一句,讲到这里难免会想到线程同步并发的事,
但ThreadLocal跟线程同步并发还是有区别的
如果用线程同步来处理并发的情况,需要对对象加锁。多线程操作的是同一个对象
而ThreadLocal上文讲了,操作的实际上是不同的对象。

照着ThreadLocal源码说吧。
获取ThreadLocal存储的副本对象

    public T get() {  
       Thread t = Thread.currentThread();// 当前的线程
       ThreadLocalMap map = getMap(t); //  取到当前线程对应的ThreadLocalMap,
       if (map != null) {   //  取副本对象操作
           ThreadLocalMap.Entry e = map.getEntry(this);
           if (e != null) {
               @SuppressWarnings("unchecked")
               T result = (T)e.value;
               return result;
           }
       }
       return setInitialValue(); 
   }

设置 ThreadLocal 存储的副本对象

     public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);  // this>>ThreadLocal对象,
        else
            createMap(t, value);
    }
 private T setInitialValue() {
        T value = initialValue();  // 设置的初始化值
        Thread t = Thread.currentThread(); // 当前的线程
        ThreadLocalMap map = getMap(t);    //  取到当前线程对应的ThreadLocalMap,每一个线程对应一个自己的ThreadLocalMap,ThreadLocalMap的key是ThreadLocal对象,value是存储的副本文件
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);   // ThreadLocalMap为空时,新生成,讲map和当前线程绑定,生成一个副本
        return value;
    }

写个demo

public class Test {
    int num = 0;
    public ThreadLocal threadLocal = new ThreadLocal() {
        @Override
        protected Integer initialValue() {
            return num;
        }
    };
    public static void main(String[] args) {
        Test test = new Test();

        CThread ct1 = new CThread(test);
        CThread ct2 = new CThread(test);
        CThread ct3 = new CThread(test);

        new Thread(ct1).start();
        new Thread(ct2).start();
        new Thread(ct3).start();
        
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        finally{
            System.out.println(Thread.currentThread().getId() + " >>> " + test.num);
        }
    }
}

public class CThread implements Runnable {
    Test test = null;
    public CThread(Test t) {
        test = t;
    }
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            int v = test.threadLocal.get();
            v++;
            test.threadLocal.set(v);
            System.out.println(
                    Thread.currentThread().getId() + "  >> " + test.threadLocal + "  >> " + test.threadLocal.get());
        }
    }

}

运行结果

微信图片_20190718151924.png

可以看到三个线程在各自针对num累加5次,结果都是一样的,证明了操作副本,彼此间互不影响的。而主线程的num仍然是0。

你可能感兴趣的:(ThreadLocal 学习笔记)