• ThreadLocal


    什么是ThreadLocal

    ThreadLocal 是 Java 里一种特殊变量,它是一个线程级别变量,每个线程都有一个 ThreadLocal 就是每个线程都拥有了自己独立的一个变量,竞态条件被彻底消除了,在并发模式下是绝对安全的变量。用于线程内共享

    使用demo

    static   ThreadLocal threadLocal=new ThreadLocal();
        public static void main(String[] args) {
            //<1>set
            threadLocal.set("dd");
            test();
        }
        public static  void  test(){
            //线程内共享 打印dd
            System.out.println(threadLocal.get());
        }

    ThreadLocal

    <1>set

    java.lang.ThreadLocal#set

        public void set(T value) {
            //获得当前线程对象
            Thread t = Thread.currentThread();
            //<3>获得t的threadLocals的成员变量 也就是ThreadLocalMap
            ThreadLocal.ThreadLocalMap map = getMap(t);
            if (map != null)
                //<4>ThreaLocal为key value为我们的值
                map.set(this, value);
            else
                //为t初始化一个ThreaLocalMap并设置值
                createMap(t, value);
        }

    <3>getMap

    java.lang.ThreadLocal#getMap

    //返回ThreadLocal.ThreadLocalMap  
     ThreadLocal.ThreadLocalMap getMap(Thread t) {
            //获得Thread的成员变量threadLocals
            return t.threadLocals;
        }

    从上面可以看出我们的数据都是存储在ThreadLocalMap,ThreadLocalMap就是一个普通的map通过ThreadLocal对象为key

    <4>set

    java.lang.ThreadLocal.ThreadLocalMap#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.
            //ThreaLocalMap内部通能数组来保存 通过Entry封装
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);
    
            for (ThreadLocal.ThreadLocalMap.Entry e = tab[i];
                 e != null;
                 //threadLocalMap是通过线性探测法来解决hash碰撞,当出现hash碰撞查找数组的下一个位置
                 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;
                }
            }
            //<5>通过内部内Entry 来存储 key为ThreadLocal value为我们set的值 并存储到数组的具体位置
            tab[i] = new  Entry(key, value); 
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

    <5>Entry

     /**
         * ThreadLocalMap静态内部类
         * WeakReference 为弱引用,当弱引用引用的的对象没有被强引用时也会被回收
         * 这里可以发现 value是强引用
         * super(k) key为ThreadLocal 传给了父类 则是弱引用
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;
    
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

    ThreadLocal内存泄露

    根据<5>处我们可以看到ThradLocal没有被强引用时就会被垃圾回收 即Entry Key会被回收,但是value还被Entry引用 ,Entry被ThreadLocalMap引用 ThreadLocalMap被Thread引用,所以在线程未被回收前对象会一直不会被回收,如果使用线程池技术 可能导致内存泄露

    如:

    public static void main(String[] args) {
            test();
        }
        public static  void  test(){
            ThreadLocal threadLocal=new ThreadLocal();
            threadLocal.set(new Student());;
        }

    弱引用Entry的keyThreadLocal对象会被回收,但是Entry还持有value的引用 ThreadLocalMap持有Entry引用  Thread持有ThreadLocalMap引用 导致内存泄露,所以当使用完要手动调用remove方法

    public static  void  test(){
            ThreadLocal threadLocal=new ThreadLocal();
            threadLocal.set("ddd");;
            threadLocal.remove();
        }

    总结

    1.ThreadLocal本质获取当前线程对象的成员变量ThreadLocalMap ThreadLocalMap通过ThreadLocal作为key存储相应的value value通过Entry封装

    2.使用map的原因是因为一个线程可以定义多个ThreadLocal

  • 相关阅读:
    Java 泛型
    face_recognition
    用于图像分割的卷积神经网络:从R-CNN到Mark R-CNN
    OpenCV探索
    基于深度学习的目标检测技术演进:R-CNN、Fast R-CNN、Faster R-CNN
    卷积神经网络CNN总结
    (4)Smali系列学习之Smali语法详解内部类
    log4j的配置信息
    C#的async和await
    Java魔法堂:String.format详解
  • 原文地址:https://www.cnblogs.com/LQBlog/p/12760740.html
Copyright © 2020-2023  润新知