解决方案 »

  1.   

    看来csdn也不过如此嘛,当我没问过。
      

  2.   

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

  3.   

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

  4.   

    恩,感觉即使用的是线程池,那个线程用完了后放回线程池继续被别的请求使用,对应的Sdf对象实例也就一直存在这个线程的ThreadLocalMap里面,这样好像也不会出什么内存泄露的问题。
      

  5.   

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

  6.   

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

  7.   

    但是这个工具是非线程安全的,多线程同时访问一个实例会存在问题的。
    哦,SimpleDateFormat 类中 public Date parse(String text, ParsePosition pos)
    {
            calendar.clear(); // Clears all the time fields        ......//对calendar的一些操作        else parsedDate = calendar.getTime();
    }线程安全隐患 原因就在于  这个 calendar线程共享了。
    简单粗暴的解决办法就是  对 使用SimpleDateFormat 的代码 synchronized
    还有就是  ThreadLocal,让SimpleDateFormat  线程本地化(每个线程都拥有自己的一份 SimpleDateFormat  ,当然calendar 也就不会在线程间共享了)。但是我有一个疑问:
    不知道楼主 具体是 怎么使用 你的这个类  DateUtil 的。貌似这个类没有没有继承Thread或是实现 Runnable。
    所以你 使用 DateUtil  getDateFormat的时候,貌似每次都可以new出的一 个SimpleDateFormat,根本没有用到 ThreadLocal的特性啊。private static ThreadLocal<DateFormat> sdf = new ThreadLocal<DateFormat>() {
    protected DateFormat initialValue() {
    return new  SimpleDateFormat("yyyy-MM-dd");
    };
    };
    如上,你的这段代码应该写在  一个线程  类中吧,而不是写在这个工具类中
      

  8.   

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

  9.   

    但是这个工具是非线程安全的,多线程同时访问一个实例会存在问题的。
    哦,SimpleDateFormat 类中 public Date parse(String text, ParsePosition pos)
    {
            calendar.clear(); // Clears all the time fields        ......//对calendar的一些操作        else parsedDate = calendar.getTime();
    }线程安全隐患 原因就在于  这个 calendar线程共享了。
    简单粗暴的解决办法就是  对 使用SimpleDateFormat 的代码 synchronized
    还有就是  ThreadLocal,让SimpleDateFormat  线程本地化(每个线程都拥有自己的一份 SimpleDateFormat  ,当然calendar 也就不会在线程间共享了)。但是我有一个疑问:
    不知道楼主 具体是 怎么使用 你的这个类  DateUtil 的。貌似这个类没有没有继承Thread或是实现 Runnable。
    所以你 使用 DateUtil  getDateFormat的时候,貌似每次都可以new出的一 个SimpleDateFormat,根本没有用到 ThreadLocal的特性啊。private static ThreadLocal<DateFormat> sdf = new ThreadLocal<DateFormat>() {
    protected DateFormat initialValue() {
    return new  SimpleDateFormat("yyyy-MM-dd");
    };
    };
    如上,你的这段代码应该写在  一个线程  类中吧,而不是写在这个工具类中
    这个是个工具类嘛,假如某一个请求对应线程a, 当我在这个请求里面调用了DateUtil的format方法或者parse方法时,如果这个线程是第一次访问这个方法时,会在线程a对应的成员变量ThreadLocalMap中存放一个键为上面类中的成员变量ThreadLocal而值为一个新创建的SimpleDateFormat,当这个讲求完结后,请求对应的线程就会回收到线程池里面。供其它讲求使用,假如说另外一个人也在页面发起一个讲求,恰好也分到了这个线程a,那么a就会直接去它的成员变量ThreadLocalMap中以ThreadLocal对象为key来取得已经存放进去的SimpleDateFormat。
    换句话说就是对应到线程池里面的每个线程,只有在该第一次调用DateUtil里面的方法时才会创建一个SImpleDateFormat对象,并存放到线程里面的ThreadLocalMap中,以后再有人讲求分配到该线程上时就直接从ThreadLocalMap里面取了,避免每次调用都new的开销,这样做也就介于singleton跟prototype之间吧,我的个人理解就是这样,不足之处望大牛们多多指点。
      

  10.   

    楼主的意思是 要通过 DateUtil工具类  给每个线程  都注入一个  ThreadLocal<DateFormat> sdf 吗?
      

  11.   


    不是给每个线程都注入一个sdf,而是给每个线程都创建一个SimpleDateFormat的实例,存储在Thread里面的成员变量
    ThreadLocalMap的value中,map的key为sdf.
      

  12.   

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

  13.   

    你的第2 点我有点不明白,ThreadLocal是没有释放 ,但是也只有这一个ThreadLocal对象实例在内存中,所有的线程不是共享这一个ThreadLocal实例的么,只是对应的SimpleDateFormat随着线程的不同而不同,这样的话感觉不释放也没影响吧?
      

  14.   

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

  15.   

    你的第2 点我有点不明白,ThreadLocal是没有释放 ,但是也只有这一个ThreadLocal对象实例在内存中,所有的线程不是共享这一个ThreadLocal实例的么,只是对应的SimpleDateFormat随着线程的不同而不同,这样的话感觉不释放也没影响吧?嗯,的确没什么影响,但是你同事不是说内存泄漏么,所以我上面说的是算内存泄漏,毕竟你用完了没释放。