非线程安全的类-SimpleDateFormat
类SimpleDateFormat主要负责日期的转换与格式化,但在多线程的环境中,使用此类容易造成数据转换及处理的不正确,因为SimpleDateFormat并不是线程安全的,我们看一段代码:
package chapter7.testsimpledateformat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyThread extends Thread{
private SimpleDateFormat sdf;
private String dateString;
public MyThread(SimpleDateFormat sdf,String dateString) {
this.sdf = sdf;
this.dateString = dateString;
}
@Override
public void run() {
try {
super.run();
Date dateRef = sdf.parse(dateString);
String newDateStr = sdf.format(dateRef).toString();
if(!newDateStr.equals(dateString)) {
System.out.println("ThreadName="+this.getName()+"报错了 日期字符串:"+dateString+" 转换成的日期为:"+newDateStr);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package chapter7.testsimpledateformat;
import java.text.SimpleDateFormat;
public class Test {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String[] dateStr = new String[] {"2000-01-01","2000-01-02","2000-01-03","2000-01-04","2000-01-05","2000-01-06","2000-01-07","2000-01-08","2000-01-09","2000-01-10"};
MyThread[] threads = new MyThread[10];
for(int i=0;i<10;i++) {
threads[i] = new MyThread(sdf, dateStr[i]);
}
for(int i=0;i<10;i++) {
threads[i].start();
}
}
}
运行结果:
ThreadName=Thread-5报错了 日期字符串:2000-01-06 转换成的日期为:2000-01-02
ThreadName=Thread-6报错了 日期字符串:2000-01-07 转换成的日期为:2000-01-01
ThreadName=Thread-2报错了 日期字符串:2000-01-03 转换成的日期为:2000-01-05
ThreadName=Thread-3报错了 日期字符串:2000-01-04 转换成的日期为:0010-01-10
ThreadName=Thread-4报错了 日期字符串:2000-01-05 转换成的日期为:2000-01-10
解决办法1:
package chapter7.testsimpledateformat;
import java.util.Date;
public class MyThread extends Thread{
private String dateString;
public MyThread(String dateString) {
this.dateString = dateString;
}
@Override
public void run() {
try {
super.run();
Date dateRef = DateTools.parse(dateString);
String newDateStr = DateTools.format(dateRef);
if(!newDateStr.equals(dateString)) {
System.out.println("ThreadName="+this.getName()+"报错了 日期字符串:"+dateString+" 转换成的日期为:"+newDateStr);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package chapter7.testsimpledateformat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTools {
private static final String DATE_FORMAT = "yyyy-MM-dd";
public static Date parse(String dateStr) throws ParseException {
return new SimpleDateFormat(DATE_FORMAT).parse(dateStr);
}
public static String format(Date date){
return new SimpleDateFormat(DATE_FORMAT).format(date);
}
}
package chapter7.testsimpledateformat;
public class Test {
public static void main(String[] args) {
try {
String[] dateStr = new String[] {"2000-01-01","2000-01-02","2000-01-03","2000-01-04","2000-01-05","2000-01-06","2000-01-07","2000-01-08","2000-01-09","2000-01-10"};
MyThread[] threads = new MyThread[10];
for(int i=0;i<10;i++) {
threads[i] = new MyThread(dateStr[i]);
}
for(int i=0;i<10;i++) {
threads[i].start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果:没有打印错误,说明问题解决,解决处理错误的原理其实就是创建多个SimpleDateFormat。
解决方法2:
package chapter7.testsimpledateformat;
import java.util.Date;
public class MyThread extends Thread{
private String dateString;
public MyThread(String dateString) {
this.dateString = dateString;
}
@Override
public void run() {
try {
super.run();
Date dateRef = DateTools.getSimpleDateFormat().parse(dateString);
String newDateStr = DateTools.getSimpleDateFormat().format(dateRef);
if(!newDateStr.equals(dateString)) {
System.out.println("ThreadName="+this.getName()+"报错了 日期字符串:"+dateString+" 转换成的日期为:"+newDateStr);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package chapter7.testsimpledateformat;
import java.text.SimpleDateFormat;
public class DateTools {
private static final String DATE_FORMAT = "yyyy-MM-dd";
private static ThreadLocal<SimpleDateFormat> tlLocal = new ThreadLocal<SimpleDateFormat>();
public static SimpleDateFormat getSimpleDateFormat() {
SimpleDateFormat sdf = null;
sdf = tlLocal.get();
if(sdf == null) {
sdf = new SimpleDateFormat(DATE_FORMAT);
tlLocal.set(sdf);
}
return sdf;
}
}
运行结果:没有输出错误,说明用ThreadLocal可以解决问题,ThreadLocal类能使线程绑定到指定的对象。

浙公网安备 33010602011771号