SimpleDateFormat线程不安全(转)
有三种方法可以解决以上安全问题。
1).使用同步
package com.bijian.study.date; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date; public class DateUtil02 implements DateUtilInterface { private SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override
public void format(Date date) {
System.out.println(dateformat.format(date));
} @Override
public void parse(String str) {
try {
synchronized(dateformat){
System.out.println(dateformat.parse(str));
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}
修改DateMainTest.java的DateUtilInterface dateUtil = new DateUtil01();为DateUtilInterface dateUtil = new DateUtil02();测试OK。
不过,当线程较多时,当一个线程调用该方法时,其他想要调用此方法的线程就要block,这样的操作也会一定程度上影响性能。
2).每次使用时,都创建一个新的SimpleDateFormat实例
package com.bijian.study.date; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date; public class DateUtil03 implements DateUtilInterface { @Override
public void format(Date date) { SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(dateformat.format(date));
} @Override
public void parse(String str) {
try {
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(dateformat.parse(str));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
修改DateMainTest.java的DateUtilInterface dateUtil = new DateUtil02();为DateUtilInterface dateUtil = new DateUtil03();测试OK。
3).借助ThreadLocal对象每个线程只创建一个实例
借助ThreadLocal对象每个线程只创建一个实例,这是推荐的方法
对于每个线程SimpleDateFormat不存在影响他们之间协作的状态,为每个线程创建一个SimpleDateFormat变量的拷贝或者叫做副本,代码如下:
package com.bijian.study.date; import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date; public class DateUtil04 implements DateUtilInterface { private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; // 第一次调用get将返回null
private static ThreadLocal threadLocal = new ThreadLocal(){
protected Object initialValue() {
return null;//直接返回null
}
}; // 获取线程的变量副本,如果不覆盖initialValue,第一次get返回null,故需要初始化一个SimpleDateFormat,并set到threadLocal中
public static DateFormat getDateFormat() {
DateFormat df = (DateFormat) threadLocal.get();
if (df == null) {
df = new SimpleDateFormat(DATE_FORMAT);
threadLocal.set(df);
}
return df;
} @Override
public void parse(String textDate) { try {
System.out.println(getDateFormat().parse(textDate));
} catch (ParseException e) {
e.printStackTrace();
}
} @Override
public void format(Date date) {
System.out.println(getDateFormat().format(date));
}
}
创建一个ThreadLocal类变量,这里创建时用了一个匿名类,覆盖了initialValue方法,主要作用是创建时初始化实例。
也可以采用下面方式创建。
package com.bijian.study.date; import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date; public class DateUtil05 implements DateUtilInterface { private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; @SuppressWarnings("rawtypes")
private static ThreadLocal threadLocal = new ThreadLocal() {
protected synchronized Object initialValue() {
return new SimpleDateFormat(DATE_FORMAT);
}
}; public DateFormat getDateFormat() {
return (DateFormat) threadLocal.get();
} @Override
public void parse(String textDate) { try {
System.out.println(getDateFormat().parse(textDate));
} catch (ParseException e) {
e.printStackTrace();
}
} @Override
public void format(Date date) {
System.out.println(getDateFormat().format(date));
}
}
修改DateMainTest.java的DateUtilInterface dateUtil = new DateUtil03();为DateUtilInterface dateUtil = new DateUtil04();或者DateUtilInterface dateUtil = new DateUtil05();测试OK。
最后,当然也可以使用apache commons-lang包的DateFormatUtils或者FastDateFormat实现,apache保证是线程安全的,并且更高效。
附:Oracle官方bug说明: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6178997
最新文章
- Fresco内存机制(Ashmem匿名共享内存)
- js中var 笔记
- PHP include()和require()方法的区别
- c++中智能输出文件
- 监控SQL Server的job执行情况
- hdu 5144 NPY and shot
- ftk学习记(waitbox篇)
- 移动端页面 iPhone + Safari 页面调试 之 正确查看网络请求的姿势
- BZOJ 2388: 旅行规划 [分块 凸包 等差数列]
- 2018年多校第四场第二题 B. Harvest of Apples hdu6333
- 工作小结:xml文件导入到oracle
- windows安装composer
- Android gravity和layout_gravity的区别
- Oracle分析函数row_number()等的使用实例
- 安装istio v1.0 详细过程和步骤
- Linux:Apache安装与启动
- React设置宽度的坑
- adb 调试出现问题
- asp.net读取用户控件,自定义加载用户控件
- xml常用的error-page