解决方案 »
- 大牛们谈谈敏捷开发的,指的什么?
- JSF 应用路径的问题,在线等~~~~~~~~~~~~~
- 为什么我的应用有时候发布不成功??
- hibernate 3.3还是hibernate 4.1?
- 有关Struts的问题,请指教
- 请问如何写socket客户端程序来实现文件的上传
- 很小的程序用package 打包后就出问题 ----- 在线等,急!!!!!
- 初学者,高分求初学方法指引,主要想学数据库程序方面!多谢!
- --- Vector的使用问题----
- EJBQL
- J2EE工作三年想学点东西
- 测试框架StrutsSpringTestCase 报错Connection timed out: connect
你同事说,ThreadLocal 不是用来解决线程安全的问题的 也是不对的说法,ThreadLocal是另一种思路,我想你也应该知道,我就不细说了。
我就说内存泄漏吧,我看不出任何问题,至于你同事的担心,我想他大概是觉得每个ThreadLocal<DateFormat> sdf在被放在不同Thread中时,如果Thread不被销毁就一直存在于内存中吧,这一点还是要看看项目需求,看线程安全和内存占用,两边有没有必要这样严格,哪边可以退步吧。
还是你同事说的是对的,ThreadLocal 更多的是用来存储线程上下文相关的信息
哦,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");
};
};
如上,你的这段代码应该写在 一个线程 类中吧,而不是写在这个工具类中
哦,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之间吧,我的个人理解就是这样,不足之处望大牛们多多指点。
不是给每个线程都注入一个sdf,而是给每个线程都创建一个SimpleDateFormat的实例,存储在Thread里面的成员变量
ThreadLocalMap的value中,map的key为sdf.
1、DateFormat不安全是发生在多个线程调用同一个DateFormat实例时造成的,而一般字符串解析我们都是写成工具类,在工具类的方法中,new SimpleDateFormat进行解析,这样是没有线程问题的,如果楼主的web项目不涉及特别巨大的日期解析操作,就没必要做过多的处理。
2、楼主使用ThreadLocal进行封装了,这样每个线程会包含一个Dateformat实例,这样的确可以解决线程安全问题,毕竟Dateformat线程间独立了,但是有点楼主请注意,ThreadLocal的声明周期跟随当前线程,楼主也说了用了线程池,这样的话使用过的线程放重新放入线程池,也就是每次用户访问之后,Threadlocal并没有释放,的确算内存泄漏了,记得用完remove(可以在filter的返回链中进行remove,ps:没有别的好地方了,你要是代码中用完就remove,这效率还不如方法1)。
3、ThreadLocal主要进行在线程的上下文中保存数据,至于解决线程安全问题,貌似没多大关系,但是巧妙的运用也能解决,楼主的例子也说明了这点。