zoukankan      html  css  js  c++  java
  • 关于Threadlocal的理解

    threadlocal

    在使用threadlocal的时候其实不是threadlocal绑定线程,而是threadlocal被绑定在线程上,

    而且可以有多个threadlocal被绑定在线程上,确切的说是作为key绑定在线程的hash表上!

    线程是主导,threadlocal是被绑定

    一个线程可以绑定多个threadlocal对象吗?

    一个线程可以和很多threadlocal对象建立间接联系,直接和线程联系的是threadlocalMap对象,threadlocalMap 对象和具体的threadlocal对象没有关系(仅仅是他的内部类而已)
    
    thread类中的这个map是以一个个threadlocal对象为key值,以用户的变量为value
    
    所以只要在当前线程作用下创建多个threadlocal实例,那thread对象中的map就会有多个记录,每一个threadlocal对象为key
    
    
    总结: 一个线程可以绑定多个threadlocal对象,线程真正绑定的是threadlocalMap,map里面会存储很多threadlocal和变量值的key-value
    

    threadlocal的静态方法withInitial()和实例方法set()的异同点

    俩个方法都能赋值
    
    withInitial()是个懒加载方法,set()是直接加载
    
    具体体现在set方法会直接判断当前线程的threadlocalMap是否为空,为空则创建之
    
    withInitial()其实是创建一个SuppliedThreadLocal对象,并重写了initialValue()方法
    

    如下:

           static final class SuppliedThreadLocal<T> extends ThreadLocal<T> {
    
            private final Supplier<? extends T> supplier;
    
            SuppliedThreadLocal(Supplier<? extends T> supplier) {
                this.supplier = Objects.requireNonNull(supplier);
            }
    
            @Override
            protected T initialValue() {
                return supplier.get();
            }
        }
    
    withInitial()方法不会给当前线程创建threadlocalMap,只会在用户调用get方法的时候判断thread.map不存在,不存在的话调用SuppliedThreadLocal.initialValue创建threadlocalMap
    

    使用threadlocal 会引起内存泄漏吗

    会,但是分场景,手动创建线程,线程用完会销毁的场景不会内存泄漏
                  线程池的场景中使用threadlocal会引起内存泄漏
    
    但是内存泄漏不是threadlocal的问题,往threadlocalmap里面的entry赋值的时候key被weakrefrence修饰(即weekreference<threadlocal>作为y被赋值给map里的entry)
    
    引用threadlocal的对象被回收了,则threadlocal在下一次GC时也会被回收,但是entry里的value不会被回收,因为该value绑定entry,绑定threadlocalmap,间接的绑定线程,若线程是线程池里面的线程,则线
    
    程不会销毁, 则entry里面的value也不会被销毁,会导致内存泄漏。
    
    而threadlocal早就被gc回收了。
    
    
    总结:内存泄漏不是threadlocal对象的问题,是因为threadlocalMap.entry 里的value 和线程是强绑定,线程回收,vaule不回收
    

    如何避免上述弱引用引发的内存泄漏?

    在使用完ThreadLocal时,及时调用它的的remove方法清除数据。
    
    remove 方法会调用 expungeStaleEntry(int staleSlot) 方法,清除key为空(key就是threadlocal)的entry
    
    总结: 及时清除threadlocal.map里面的vaule 就可以避免内存泄漏,(ThreadLocal的回收不用担心,weekreference修饰,不用的时候会自动GC)
    

    InheritableThreadLocal

    解决父线程传递本地变量到子线程的
    https://blog.csdn.net/hewenbo111/article/details/80487252
    

    InheritableThreadLocal 是如何在父子线程间传递变量的

        因为Thread类有2个变量:  ThreadLocal.ThreadLocalMap threadLocals = null; // 线程本地变量
                               ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; //继承线程本地变量
    
        再然后就是线程的构造方法了
        public Thread() {
            init(null, null, "Thread-" + nextThreadNum(), 0);
        }
    
        构造方法里面的init的重载方法
    
        private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) {}
    
    
        最后一个参数: boolean inheritThreadLocals 表示是否需要从父线程继承 inheritableThreadLocals 属性
    
        如下判断:
    
        if (inheritThreadLocals && parent.inheritableThreadLocals != null){  // 如果重载的init方法里的布尔值inheritThreadLocals为true
            this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);//则将当前子线程的inheritableThreadLocals属性设置
    //为父线程的inheritableThreadLocals属性,即把父线程额threadlocalMap 赋值给子线程的 inheritableThreadLocals字段
        }
                
        我们知道线程从threadlocal里调用get()方法获取绑定的参数的时候主要是先调用getMap()方法取出对于的threadlocalMap对象
    
        恰好 InheritableThreadLocal 重写了 getMap() 方法
    
          ThreadLocalMap getMap(Thread t) {
           return t.inheritableThreadLocals;
        }
     
        void createMap(Thread t, T firstValue) {
            t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
        }
    
        若实现类是InheritableThreadLocal对象时getMap方法取的是当前线程的ThreadLocal.ThreadLocalMap inheritableThreadLocals 属性,
    
        而当前线程的该属性已经在构造当前线程对象的时候从父线程里面copy出来了,并且赋值了(详见上面Thread类的重载的init方法)
    
    
        总结下来就是:
    
        当前线程里面调用threadlocal对象的get()方法取值的时候,如果threadlocal对象是ThreadLocal时,则从threadLocals属性取ThreadLocalMap,
                                                            如果threadlocal对象是InheritableThreadLocal时,则从inheritableThreadLocals属性取ThreadLocalMap,
    
        再从取出的Map里面取值。
    
    
        所以能做到父子线程传递变量
    
    

    TransmittableThreadLocal

    解决线程池里面变量传递的问题
    https://blog.csdn.net/hewenbo111/article/details/90053105
    
    基础决定深度啊!
  • 相关阅读:
    Linux 删除多余IP地址
    linux 变更网卡后无法联网
    eureka 参数
    C# 一般处理程序使用session注意事项
    asp.net web 简单使用cookie
    asp.net ajax post 请求
    Ajax 的基本使用以及get请求
    asp.net 错误页
    C# winfrom 跨线程访问文本框
    C# winfrom 打印到Excel中
  • 原文地址:https://www.cnblogs.com/YJZUUID/p/13731133.html
Copyright © 2011-2022 走看看