ope体育注册页_ope电竞竞猜|ope电竞官网
ope体育注册页

烤箱烤红薯,结婚请柬-ope体育注册页_ope电竞竞猜|ope电竞官网

admin admin ⋅ 2019-05-20 07:01:28

专心于Java范畴优质技能,欢迎重视

作李俊豪现在相片者: 邱东六幺水调家家唱下一句 IT一刻钟

又是一个风和日丽的早上。

这天小美遇到了一个难题。




本来小美在做用户服务鉴权的时分,需求依据每个恳求获取token:

然后通过微信特别姓名带花印层层的调用,在事务代码里依据认证信息进行权限的判别,也便是鉴权。

小美心里揣摩着,假如每个办法参数中都传递SecurityCon关音山text信息,就显的过分冗余,并且看着也丑恶。

那么怎样才干隐式传递参数呢?

这个当然难不倒小美,她决议用ThreadLocal来传递这个变量:

全体思路上便是烤箱烤红薯,成婚请柬-ope体育注册页_ope电竞竞猜|ope电竞官网将SecurityContext放入ThreadLocal,这样当一个线程缘起生灭的时分,这个值会贯穿一直。

完美,小美喜滋滋的提交了代码,然后发布出去了。

成果第二天体系就出现异常了,分明是这个用户A的建议的恳求邑辉一贵,到了数据库中,却发现是操作人是用户B的信息,一时间权限大乱。

完蛋了。。。



这是为什么呢?烤箱烤红薯,成婚请柬-ope体育注册页_ope电竞竞猜|ope电竞官网

咱们得先扯一扯Thr甘愿代替你吉他谱eadLocal,Thread,ThreadLocalMap之间的爱恨情仇。


ThreadLocal原理图


图片说明:

1.Thread即线程,内部有一个ThreadLocal.ThreadLocalMap,key值是ThreadLocal,value值是指定的变量值;

2.Th烤箱烤红薯,成婚请柬-ope体育注册页_ope电竞竞猜|ope电竞官网readLocalMap内部有一个Entry数组,用来存储K-V值,之所以是数组,而不是一个Entry,是由于一个线程或许对应有多个T烤箱烤红薯,成婚请柬-ope体育注册页_ope电竞竞猜|ope电竞官网hreadLocal;

3.ThreadLocal目标在线程外倒挂姐生成,多线程同享g2023一个ThreadLocal目标,生成时需指定数据类型,每个ThreadarashramniLocal目标都自定义了不同的threadLocalH赖诗滢ashCode;

4.ThreadLocal.set 首要依据当时线程Thread找到对应的ThreadLocalMap,然后将ThreadLocal的threadLocalHashCode转换为ThreadLocalMap里的Entry数组下标,并寄存数据于ady9netEntry[]中;

5.ThreadLocal.get 首要依据当时线程Thread找到对应的ThreadLocalMap,然后将ThreadLocal的threadLocalHashCode转换为ThreadLocalMap里的Entry数组下标,依据下标从Entry[]中取出对应的数据;

6.由于Thread内部的ThreadLoca烤箱烤红薯,成婚请柬-ope体育注册页_ope电竞竞猜|ope电竞官网l.ThreadLocal龚磬冬Map烤箱烤红薯,成婚请柬-ope体育注册页_ope电竞竞猜|ope电竞官网目标是每个线程私有的,所以做到了数据独立。

所以咱们知道了Thr烤箱烤红薯,成婚请柬-ope体育注册页_ope电竞竞猜|ope电竞官网eadLocal是怎么完成线程私有变量的。

可是问题来了,假如线程数许多,一直往ThreadLocalMap中存值,那内存岂不是要撑死了?

当然不是,设计者运用了弱引证来处理这个问题:

static class Entry extends WeakReference
Object value;
Entry(ThreadLocal
super(k);
value = v;
}
}

不过这儿的弱引证仅仅针对key。每个key都弱引证指向ThreadLocal。当把Th冷宫弃后很绝情readLocal实例置为null今后,没有任何强引证指向ThreadLocal实例,所以ThreadLocal将会被GC收回。但是,value不能被收回,由于当时线程存在对value的强引证。只要当时线程结束毁掉后,强引证断开,一切值才将悉数被GC收回,由此可推断出,只要这个线程被收回了,ThreadLocal以及value才会真正被收回。

听起来很正常?



那假如咱们运用线程池呢?常驻线程不会被毁掉。这就完蛋了,ThreadLocal和value永久无法被GC收回,形成内存走漏那是必定的。

而咱们的恳求进入到体系时,并不是一梧桐轩个恳求生成一个线程,而是请莫科周雅菲求先进入到线程池,再由线程池调配出瑾年春一个线程进行履行,履行结束后放回线程池,这样就会存在一个线程屡次被复用的状况,这就产生了这个线程此迷情小叔子次操作中获取到了前次操作的值。

怎样办呢?



处理办法便是每次运用完ThreadLocal目标后,都要调用其remove办法,铲除ThreadLocal中的内容。

示例:

输出:

0
1
0
2
3
1

这儿便是过错的。

假如每次履行完调用remove:

@Override
public void run() {
int value = sequencer.g叶育青e乐乎ptt().getAndIncrement();
System.out.println("-------"+value);
sequencer.remove();
}

输出:

0
0
0
0
0
0

输出则正常。

好了,本期就提到这儿,转发加点赞,是我共享的最大动力~

相关新闻

admin

admin

TA太懒了...暂时没有任何简介

精彩新闻