资讯专栏INFORMATION COLUMN

慎用ThreadLocal

harriszh / 2208人阅读

摘要:另载于是个很爽的东西,线程安全,能当全局变量来用别。第一家公司,使用框架老技术,现代人可以理解为类似,对每个请求都套上,进入时把写入,返回或抛注意时清理。第二家公司,某次引入一个设计,也用了来传递上下文信息,有的地方没能清掉。

另载于 http://www.qingjingjie.com/blogs/12

ThreadLocal是个很爽的东西,线程安全,能当全局变量来用(别!)。

上一篇末尾提到ThreadLocal的妙用,这东西确实在框架实现中很常用。不过一定要小心啊。

先告诉大家一个安全秘诀:try-finally大法,百战百胜!(一定要在finally里清空ThreadLocal)

我职业生涯遇到最棘手的并发bug都是ThreadLocal造成的,称之为ThreadLocal污染问题。

第一家公司,使用Seam框架(老技术,现代人可以理解为类似Spring MVC),Seam对每个请求都套上Filter,进入时把context写入ThreadLocal,返回或抛Exception(注意)时清理ThreadLocal。而我们用了很多的库,有的库会抛Error,用catch(Exception e)是抓不住的。这就导致有时ThreadLocal没有被清掉,而服务器用的是线程池,线程会复用啊,那下次请求是不是可能读到错误的context呢?听起来好严重啊!

倒也不会,Seam遇到下一个请求又会把新的context写入ThreadLocal,覆盖旧值,就算旧值没释放也不要紧。然而!我们的系统有的模块没有用Seam,而我们有个内部框架,为了兼容性,会检测当前线程是否存在Seam context,如果存在,就从context取对象,如果不存在,就另寻蹊径。有的Filter挂在Seam Filter前面,如果那个Filter调到内部框架,就会先检测当前线程是否存在Seam context,就读到上次的context了。

这样就会出现一些诡异的运行结果,理论上污染会逐渐扩大,直到服务器重启才恢复。更诡异的是如果被污染的线程下次遇到了Seam Filter,覆盖旧值,就又恢复正常了,让人抓不到。

最后当然是诊断并解决了这个问题啦(只能靠推理o(╯□╰)o)。我顺便看了Spring MVC的代码,是用了try-finally大法的,经得起考验。

第二家公司,某次引入一个设计,也用了ThreadLocal来传递上下文信息,有的地方没能清掉ThreadLocal。于是诡异bug冒出来,百分之一概率出现各种稀奇古怪的运行结果,看不出规律,就是怪。所以大家还是能看到一点规律的——那就是没有规律!

现在大家应该明白要怎么对待ThreadLocal了吧。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64533.html

相关文章

  • ThreadLocal 内部实现和应用场景(慎用,可能有内存泄露)

    摘要:而应用场景更多是想共享一个变量,但是该变量又不是线程安全的,那么可以用维护一个线程一个实例。因为创建这个对象本身很费时的,而且我们也知道本身不是线程安全的,也不能缓存一个共享的实例,为此我们想到使用来给每个线程缓存一个实例,提高性能。 很多人都知道java中有ThreadLocal这个类,但是知道ThreadLocal这个类具体有什么作用,然后适用什么样的业务场景还是很少的。今天我就尝...

    heartFollower 评论0 收藏0
  • 手撕面试官系列(七):面试必备之常问并发编程高级面试专题

    摘要:如何在线程池中提交线程内存模型相关问题什么是的内存模型,中各个线程是怎么彼此看到对方的变量的请谈谈有什么特点,为什么它能保证变量对所有线程的可见性既然能够保证线程间的变量可见性,是不是就意味着基于变量的运算就是并发安全的请对比下对比的异同。 并发编程高级面试面试题 showImg(https://upload-images.jianshu.io/upload_images/133416...

    Charles 评论0 收藏0
  • JAVA单例(Singleton)实现的几种方式(多线程安全)

    摘要:缺点每次调用都有线程开销延迟初始化单例默认构造方法为,避免用户用构造出新对象获取单例的静态工厂同步方法延迟初始化单例使用同步方法保证多线程操作只实例化一个实力单例模式。 主要分为两种: 直接初始化 延迟初始化 直接初始化 直接初始化final静态成员 线程安全:JVM保证final静态成员只会被初始化一次 公有静态成员是个final域,直接引用成员获取单例 /** * 公有静态成...

    smartlion 评论0 收藏0
  • Java面试题必备知识之ThreadLocal

    摘要:方法,删除当前线程绑定的这个副本数字,这个值是的值,普通的是使用链表来处理冲突的,但是是使用线性探测法来处理冲突的,就是每次增加的步长,根据参考资料所说,选择这个数字是为了让冲突概率最小。 showImg(https://segmentfault.com/img/remote/1460000019828633); 老套路,先列举下关于ThreadLocal常见的疑问,希望可以通过这篇学...

    Maxiye 评论0 收藏0
  • ThreadLocal详解

    摘要:在方法中取出开始时间,并计算耗时。是一个数组主要用来保存具体的数据,是的大小,而这表示当中元素数量超过该值时,就会扩容。如果这个刚好就是当前对象,则直接修改该位置上对象的。 想要获取更多文章可以访问我的博客 - 代码无止境。 什么是ThreadLocal ThreadLocal在《Java核心技术 卷一》中被称作线程局部变量(PS:关注公众号itweknow,回复Java核心技术获取该...

    2501207950 评论0 收藏0

发表评论

0条评论

harriszh

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<