慎用ThreadLocal

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了吧。原文转载至:http://www.ynxxfk.com/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值