ThreadLocal引起内存泄露

J2EE 码拜 9年前 (2016-05-21) 1351次浏览
代码如下:
public class DateUtil {
private static ThreadLocal<DateFormat> sdf = new ThreadLocal<DateFormat>() {
protected DateFormat initialValue() {
return new  SimpleDateFormat(“yyyy-MM-dd”);
};
};
public static DateFormat getDateFormat(ThreadLocal<DateFormat> tl) {
return tl.get();
}
public static String format(Date date) {
if (date == null) {
return “”;
}
return getDateFormat(sdf).format(date);
}
public static Date parse(String st) throws ParseException {
return  getDateFormat(sdf).parse(st);
}
}
最近在做一个Web项目,由于SimpleDateFormat是非线程安全的,所以想到用ThreadLocal来封装了一下,项目用到了线程池,同事说这样写的话会造成实例对象不能回收,从而导致内存泄露,(ps:同事说ThreadLocal 不是用来解决线程安全的问题的)希望大神们给看看,这样用到底能不能行,假如真的会导致内存泄露,烦请剖析一下。
解决方案

10

首先,你这样写是不会造成内存泄漏或实例对象不能回收问题的。
你同事说,ThreadLocal 不是用来解决线程安全的问题的 也是不对的说法,ThreadLocal是另一种思路,本人想你也应该知道,本人就不细说了。
本人就说内存泄漏吧,本人看不出任何问题,至于你同事的担心,本人想他大致是觉得每个ThreadLocal<DateFormat> sdf在被放在不同Thread中时,假如Thread不被销毁就一直存在于内存中吧,这一点还是要看看项目需求,看线程安全和内存占用,两边有没有必要这样严格,哪边可以退步吧。

10

个人觉得,只要你的线程生命周期不长,完全没问题的,JDK7 的 ThreadLocalRandom 也是相似的做法。
假如你觉得不保险,可以加个 remove方法,方法结束的 finally 块里执行 ThreadLocal.remove
还是你同事说的是对的,ThreadLocal 更多的是用来存储线程上下文相关的信息

10

用完后本人释放吧。

10

DateFormat  只是一个工具而已,为什么要 线程隔离呢?

15

做个synchronized静态方法,直接用DateFormat  ,简单粗暴又有效。
你同事担心的,可能是怕页面并发请求量很大的时候,每一个请求都要分配一个ThreadLocal,会占用很多内存。至于回收,感觉ThreadLocal所属线程结束了,它也就结束了。

15

同事说这样写的话会造成实例对象不能回收,从而导致内存泄露
你问下你同事为什么。说不出为什么那他的结论就没有依据。
至于你的,本人看不出有啥问题

5

为何都这么轻易的使用内存泄露呢?java 一般的代码顶多是内存溢出。

20

看了下题主的题目,这种方式处理还是可行的。有几点建议:
1、DateFormat不安全是发生在多个线程调用同一个DateFormat实例时造成的,而一般字符串解析我们都是写成工具类,在工具类的方法中,new SimpleDateFormat进行解析,这样是没有线程问题的,假如题主的web项目不涉及特别巨大的日期解析操作,就没必要做过多的处理。
2、题主使用ThreadLocal进行封装了,这样每个线程会包含一个Dateformat实例,这样的确可以解决线程安全问题,毕竟Dateformat线程间独立了,但是有点题主请注意,ThreadLocal的声明周期跟随当前线程,题主也说了用了线程池,这样的话使用过的线程放重新放入线程池,也就是每次用户访问之后,Threadlocal并没有释放,的确算内存泄漏了,记得用完remove(可以在filter的返回链中进行remove,ps:没有别的好地方了,你要是代码中用完就remove,这效率还不如方法1)。
3、ThreadLocal主要进行在线程的上下文中保存数据,至于解决线程安全问题,貌似没多大关系,但是巧妙的运用也能解决,题主的例子也说明了这点。

5

个人觉得ThreadLocal这个类就不应该存在  最好别用  SimpleDateFormat不是线程安全的  假如你想要用这个去parse  那么每次就new  这样也没什么  没占多少空间  假如只是想format  可以用commons的FastDateFormat  它线程安全

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明ThreadLocal引起内存泄露
喜欢 (0)
[1034331897@qq.com]
分享 (0)