由于项目是运行在多线程环境下的,SimpleDateFormat对于日期的转换就出问题了。昨天测试部邮件通知我们日志的开始时间大于结束时间的时候我头都大了。经查找,发现是由于SimpleDateFormat线程不安全引起的。哎,以前一直在用这个类,从来没关注过。
现将测试代码发上。
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang.time.FastDateFormat;
public class Main {
private static final DateFormatUtils dateUtil = new DateFormatUtils();
private static final SimpleDateFormat sdf = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss.SSS");
private static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>();
private SimpleDateFormat getFormat() {
SimpleDateFormat sdf = threadLocal.get();
if (sdf == null) {
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
threadLocal.set(sdf);
}
return sdf;
}
public void foo(Date d1, Date d2) throws ParseException {
String sd1 = getFormat().format(d1);
String sd2 = getFormat().format(d2);
Date dd1 = getFormat().parse(sd1);
Date dd2 = getFormat().parse(sd2);
if (dd1.getTime() - dd2.getTime() > 0) {
System.err.println("Error:" + sd1 + ">" + sd2);
}
}
public void foo2(Date d1, Date d2) throws ParseException {
String sd1 = DateFormatUtils.format(d1, "yyyy-MM-dd HH:mm:ss.SSS");
String sd2 = DateFormatUtils.format(d2, "yyyy-MM-dd HH:mm:ss.SSS");
Date dd1 = DateUtils.parseDate(sd1,
new String[] { "yyyy-MM-dd HH:mm:ss.SSS" });
Date dd2 = DateUtils.parseDate(sd1,
new String[] { "yyyy-MM-dd HH:mm:ss.SSS" });
if (dd1.getTime() - dd2.getTime() > 0) {
System.err.println("Error:" + sd1 + ">" + sd2);
}
}
public static void main(String[] args) throws ParseException {
Main m = new Main();
Thread thread1 = new Thread(new Thread1(m));
thread1.start();
Thread thread2 = new Thread(new Thread1(m));
thread2.start();
}
}
两个线程:
import java.text.ParseException;
import java.util.Date;
public class Thread1 implements Runnable{
private Main main;
public Thread1(Main main){
this.main = main;
}
public void run() {
for(;;){
try {
main.foo(new Date(), new Date());
} catch (ParseException e) {
e.printStackTrace();
}
}
}
}
import java.text.ParseException;
import java.util.Date;
public class Thread2 implements Runnable{
private Main main;
public Thread2(Main main){
this.main = main;
}
public void run() {
for(;;){
try {
main.foo2(new Date(), new Date());
} catch (ParseException e) {
e.printStackTrace();
}
}
}
}
如上,如果Main类中foo方法使用静态常量sdf进行转换很多错误的打印语句。如果使用ThreadLocal类绑定SimpleDateFormat则可以解决线程不统一的问题。
当然使用Apache提供的类DateFormatUtils以及DateUtils类进行日期的转换也可以解决线程的问题,如foo2方法。