论坛首页 Java企业应用论坛

学习Spring必学的Java基础知识(6)----ThreadLocal

浏览 72608 次
该帖已经被评为精华帖
作者 正文
   发表时间:2012-08-09  
学习了,清晰易懂,谢谢
0 请登录后投票
   发表时间:2012-08-09   最后修改:2012-08-09
downpour 写道
jwx0925 写道
我们公司的应用(访问量很大)已经出现过几次这样的问题,由于ThreadLocal使用不当,造成系统频繁内存溢出。
ThreadLocal的Entry的弱引用问题,网上也有很多文章:http://blog.163.com/greencoat_man@126/blog/static/10261923520106410928943/

其实,只要不泛滥使用ThreadLocal,正确的使用,一般情况下,是没有问题的。


即使是用线程池,内存溢出的可能性我认为也很小,不过我没有研究过web容器的线程池,结论不敢妄下。如果一个Web容器的线程池连ThreadLocal的问题都没有考虑到,这个Web容器的设计只能打不及格。


从原理上看,如果在线程池+ThreadLocal的场景下,如果不手工删除,
1)可能会发生内存泄漏,但是概率很小,基本可以不考虑。
2)一定会延长垃圾回收时间,降低内存使用率,但影响很不会大。

场景1:没有线程池的场景
  1.用户A请求来了,创建一个新线程T1;
  2.创建UserSession对象,将其绑定到ThrealLocal中;
  3.完成用户请求,返回响应;
  4.线程T1销毁;
  5.ThreadLocal中T1所对应的UserSession元素移除,UserSession可被垃圾回收。

场景2:有线程池的场景

  1.用户A请求来了,从线程池获取可用线程T1;
  2.创建UserSession对象,将其绑定到ThrealLocal中;
  3.完成用户请求,返回响应;
  4.线程T1返回线程池;
  5.ThreadLocal中T1所对应的UserSession元素不会移除,UserSession还不能被垃圾回收;

  6.过了若干时间(一会儿)...

  7.用户B请求来了,从线程池获取线程,发现T1可用,返回T1
  8.创建用户B的UserSession对象,将其绑定到ThrealLocal中,ThreadLocal中 (T1,用户A UserSession)的项目
    将被覆盖成(T1,用户B UserSession);
  9.用户A的UserSession 可被垃圾回收。

对比场景1和场景2,我们发现用户A的UserSession 最终都是会被回收的,只不过场景1会“比较及时地”回收,而
场景2中,回收得不够及时。

   如果应用中有很多东西都在放在ThreadLocal(有很多ThreadLocal变量),那么还是要考虑一下这种延长垃圾回收对内存的影响的。我给出一个公式:
  
引用
假设应用中有N个ThreadLocal的变量,线程池的大小为M,每个ThreadLocal变量占用内存平均为P,则因这种延迟
回收而战胜的内存最大值T为:
T  = N*M*P


   举例来说,你的应用中有20个ThreadLocal变量 ,Web服务器的线程池最大线程数为 500,每个ThreadLocal变量平均大小为1K,则因延迟而造成的内存泄漏最大量为:
  
   20*500*1K = 10M

   注意以上是极端情况下的泄漏量,由于线程池本身有idle线程一段时间后自动销毁的机制,另考虑到线程池的线程复用率,并发性极高,因此实际的内存泄漏量要小很多,象上面的情况,我估计也就是1M左右吧。
  
   由于手工清除ThreadLocal变量会让代码复杂性变高,因此一般情况下,是不用去考虑的,等真的发生了问题再去关注这块吧。




0 请登录后投票
   发表时间:2012-08-29  
讨论很精彩。 这下差不多理解了ThreadLocal. 感谢啊
0 请登录后投票
   发表时间:2012-10-17  
mazzystar 写道
stamen 写道
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式:访问串行化,对象共享化。而ThreadLocal采用了“以空间换时间”的方式:访问并行化,对象独享化。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。


说的真好,赞一个

这个好像在陆舟的struts2 技术内幕看大过,难道楼主是陆舟大神。。。
0 请登录后投票
   发表时间:2012-10-18  
jasshine 写道
mazzystar 写道
stamen 写道
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式:访问串行化,对象共享化。而ThreadLocal采用了“以空间换时间”的方式:访问并行化,对象独享化。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。


说的真好,赞一个

这个好像在陆舟的struts2 技术内幕看大过,难道楼主是陆舟大神。。。


陆舟是我。楼主的总结其实也来源于网上,我之前的总结也是。我更多从源码角度解读,楼主通过实例解读。异曲同工而已。
0 请登录后投票
   发表时间:2012-10-21  
downpour 写道
jasshine 写道
mazzystar 写道
stamen 写道
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式:访问串行化,对象共享化。而ThreadLocal采用了“以空间换时间”的方式:访问并行化,对象独享化。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。


说的真好,赞一个

这个好像在陆舟的struts2 技术内幕看大过,难道楼主是陆舟大神。。。


陆舟是我。楼主的总结其实也来源于网上,我之前的总结也是。我更多从源码角度解读,楼主通过实例解读。异曲同工而已。

额。。。我买了您的那本struts2技术内幕,感觉写的真好,很有条理。什么时候也给我们写个spring技术内幕吧。
0 请登录后投票
   发表时间:2012-10-22  
很精彩,也很使用,楼主辛苦。
0 请登录后投票
   发表时间:2013-02-07  
学习了,通俗易懂
0 请登录后投票
   发表时间:2013-02-27  
请问下LZ

《Spring 3.x企业应用开发实战》这本书适合什么人群看呢?我买了本《Spring技术内幕2》,看起来有点吃力,一开始就是讲底层代码。

请LZ给点意见
0 请登录后投票
   发表时间:2013-03-07  
那几篇讲的都很好,多谢楼主,受益匪浅啊
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics