SimpleDateFormat 是线程不安全类,在定义为static时可能出现线程安全问题;推荐使用DateUtils工具类。下面的示例将给出错误的和正确的代码。
首先是错误的代码,执行Demo会发现,在某些竞态条件下报错。
package wrong;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by Administrator on 2016/10/25.
*/
public class MyThread extends Thread {
private String dateString;
private SimpleDateFormat simpleDateFormat;
public MyThread(String dateString, SimpleDateFormat simpleDateFormat) {
super();
this.dateString = dateString;
this.simpleDateFormat = simpleDateFormat;
}
@Override
public void run() {
Date dateRef = null;
try {
dateRef = simpleDateFormat.parse(dateString);
String newDateString = simpleDateFormat.format(dateRef).toString();
if (!newDateString.equals(dateString))
System.out.println("thread" + this.getName() + "报错了 字符串=" + dateString + " 转换成" + newDateString);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
package wrong;
import java.text.SimpleDateFormat;
public class Demo {
static SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd");
public static void main(String[] args) {
String[] dateStringArray = new String[]{
"2000-01-01", "2001-01-01", "2002-01-01", "2003-01-01", "2004-01-01",
"2005-01-01", "2006-01-01", "2007-01-01", "2008-01-01", "2009-01-01"
};
MyThread[] myThreads = new MyThread[10];
for (int i = 0; i < 10; i++) {
myThreads[i] = new MyThread(dateStringArray[i],simpleDateFormat);
}
for (int i = 0; i < 10; i++)
myThreads[i].start();
}
}
下面是正确的代码,利用了ThreadLocal的特性,保证每个线程有且只有一个专用的SimpleDateFormat.
package correct;
import java.text.ParseException;
import java.util.Date;
public class MyThread extends Thread {
private String dateString;
public MyThread( String dateString) {
super();
this.dateString = dateString;
}
@Override
public void run() {
Date dateRef = null;
try {
dateRef = DateUtils.getSimpleDateFormat("yyyy-MM-dd").parse(dateString);
String newDateString = DateUtils.getSimpleDateFormat("yyyy-MM-dd").format(dateRef).toString();
if (!newDateString.equals(dateString))
System.out.println("thread" + this.getName() + "报错了 字符串=" + dateString + " 转换成" + newDateString);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
package correct;
import java.text.SimpleDateFormat;
/**
* Created by Administrator on 2016/10/25.
*/
public class DateUtils {
private static ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal=new ThreadLocal<SimpleDateFormat>();
public static SimpleDateFormat getSimpleDateFormat(String pattern){
if(simpleDateFormatThreadLocal.get()==null)
simpleDateFormatThreadLocal.set(new SimpleDateFormat(pattern));
return simpleDateFormatThreadLocal.get();
}
}
package correct;
public class Demo {
public static void main(String[] args) {
String[] dateStringArray = new String[]{
"2000-01-01", "2001-01-01", "2002-01-01", "2003-01-01", "2004-01-01",
"2005-01-01", "2006-01-01", "2007-01-01", "2008-01-01", "2009-01-01"
};
MyThread[] myThreads = new MyThread[10];
for (int i = 0; i < 10; i++) {
myThreads[i] = new MyThread(dateStringArray[i]);
}
for (int i = 0; i < 10; i++)
myThreads[i].start();
}
}
SimpleDateFormat的线程安全性是编码时一个常见的坑,要注意正确使用。
提供给想深入学习和提高JAVA并发编程能力的同学,欢迎收听https://www.zhihu.com/lives/1018219399903387648
提供给想学习云计算的同学,欢迎收听https://www.zhihu.com/lives/1046567982750281728