美文网首页
ThreadLocal 学习笔记

ThreadLocal 学习笔记

作者: heheworld | 来源:发表于2019-07-18 15:49 被阅读0次

    在看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<Integer> threadLocal = new ThreadLocal<Integer>() {
            @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 学习笔记

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