ThrealLocal(传参导致接口污染、线程安全)

1、进程-线程:

	“进程是资源分配的基本单位,线程是CPU调度和分派的基本单位”

相信新人百度时见过这句话,反正我当时一脸懵逼。
进程:例如QQ。登录时,启动了QQ这个进程,给它分配了一块内存,占用了一部分总线、寄存器等资源。
线程:例如使用QQ视频的同时刷朋友圈,此时是两个线程在cpu中执行,一线程视频通信,一线程刷新朋友圈。看吧,cpu直接调度线程执行程序。

2、线程Thread与ThreadLocal

请添加图片描述
看,Thread中依赖了ThreadLocal的一个内部类ThreadLocalMap;
哥哥,Map呀,“K-V”结构呗(但此Map非java.util.Map,不会变链表红黑树,当发生hash冲突时,往后面线性查找);
可以这么设想:Thread中有个属性Map,好比一个口袋;V=要存入的值,K=把V存进来的ThreadLocal实例。ThreadLocal中set()展示

    public void set(T value) {
    	//获取当前线程
        Thread t = Thread.currentThread();
        //获取当前线程的口袋
        ThreadLocalMap map = getMap(t);
        if (map != null)
        	//存入this实例,value要存的值
            map.set(this, value);
        else
        	//创建口袋,并存入
            createMap(t, value);
    }

SoEasy yes no yes,那取的时候呢:

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //没获取到,设置到口袋中,并返回当前值
        return setInitialValue();
    }

大致就是这么个东西,第一次看纠结于为什么用ThreadLocal实例做K…

3、内存泄露?

   static class Entry extends WeakReference<ThreadLocal<?>> {
       Object value;
       Entry(ThreadLocal<?> k, Object v) {
       //调用WeakReference构造,参数是ThreadLocal实例
           super(k);
           value = v;
       }
   }

ThreadLocalMap中存放是Entry,在创建时,将ThreadLocal当前实例变成了虚引用(不是一threaLoca本身就是虚引用),虚引用么,GC时被回收,导致V取不出来,导致内存泄露,真的吗?????

内存条件:

1、线程被复用,线程池么,可以满足;
2、用完没用remove()。两个条件满足就会泄露??
假设没remove,GC回收了K,确实线程中的V目前无法销毁,当此线程第二次执行时,在调用set方法后,有个cleanSomeSlots()的方法(清除所有K=null的V),并且get,remove方法也调用了。。
所以只要该线程复用时调用了threadLocal中方法,就会清理所有的K=null的V,如何泄露??
所以为啥map中K用虚引用,真的是猴精猴精的哈

那还有可能说K一值有强引用存在,行,bean的全局变量是吧,你能创建多少个才能创建到oom的地步。。

总结:线程复用 && (Thread被不断存入值且threalLocal有强引用 || 存入了一个超大对象,接下来的程序执行jvm内存不够) 会引发oom.

so,兄弟们,除了存入超大对象导致内存不够用,不停创建有强引用的K去往thread中存值,就算没调用remove,是一般不会oom的。finally中调用了remove,是99.9%不会发生oom,剩下就一种可能,存了一个超大对象,程序运行内存不够了

4、为啥建议使用static修饰ThreadLocal,并最好是全局变量?

解:节省new时消耗资源呗,并且也方便在别的类使用,直接类名.出来

5、使用场景

1、传参,有很多函数a调b,b调c,c调 d。d新增一个形参,总不能从a直接传过去吧,此时通过线程带过去;
2、线程安全:simpDataFormate用过吧,多线程用同一个对象会返回意想不到的结果o。若你通过深拷贝给每个线程来一份,那肯定就不会有问题了。
比如spring中事务控制,在当前线程中维护connect,通过AOP用到了参数传递,也保证了事务的安全性(本线程开启的,只能本线程关闭)

感谢大家观看!我也知道说的不是很清楚,文字真的好难描述清除。一起加油吧!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值