@[TOC]
前言
类 SimpleDateFormat 主要负责日期的转换与格式化,但在多线程的环境中,使用此类容易造成数据转换及处理的不准确,因为 SimpleDateFormat 类并不是线程安全的。
1.出现异常
本实例将实现使用类 SimpleDateFormat 类在多线程的环境中处理日期但得出的结果却是错误的情况,这也是再多线程环境开发中容易遇到的问题。
创建名称为7.4.1项目。
创建MyThread.java类代码如下:
import java.text.ParseException;
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) {
super();
this.sdf = sdf;
this.dateString = dateString;
}
@Override
public void run() {
try {
Date dateRef = sdf.parse(dateString);
String newDateString = sdf.format(dateRef).toString();
if (!newDateString.equals(dateString)) {
System.out.println("ThreadName= " + this.getName()
+ "报错了 日期字符串: " + dateString + " 转换成的日期为: " + newDateString);
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}
创建运行类Test.java代码如下:
import java.text.SimpleDateFormat;
public class Test {
public static void main(String[] args) {
//共享变量SimpleDateFormat 导致 java.lang.NumberFormatException: multiple points
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String[] dateStringArray = new String[]{"2000-01-01", "2001-02-02", "2003-03-03", "2004-04-04","2004-04-05","2004-04-06","2004-04-07"};
MyThread[] threadArray = new MyThread[7];
for (int i = 0; i < dateStringArray.length; i++) {
threadArray[i] = new MyThread(sdf, dateStringArray[i]);
}
for (int i = 0; i < dateStringArray.length; i++) {
threadArray[i].start();
}
}
}
程序运行后的结果如下所示:
ThreadName= Thread -2 报错了 日期字符串: 2003 -03 -03 转换成的日期为: 2300 -04 -07
ThreadName= Thread -4 报错了 日期字符串: 2004 -04 -05 转换成的日期为: 2300 -04 -07
从控制台中打印的结果来看,使用单例的 SimpleDateFormat 类在多线程的环境中处理日期,极易出现日期转换错误的情况。
2.解决异常方法 1
创建名称为7.4.2项目。
创建MyThread.java类代码如下:
import java.text.ParseException;
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) {
super();
this.sdf = sdf;
this.dateString = dateString;
}
@Override
public void run() {
try {
Date dateRef = DateTools.parse("yyyy-MM-dd", dateString);
String newDateString = DateTools.format("yyyy-MM-dd", dateRef);
if (!newDateString.equals(dateString)) {
System.out.println("ThreadName= " + this.getName()
+ "报错了 日期字符串: " + dateString + " 转换成的日期为: " + newDateString);
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}
创建类DateTools.java代码如下:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.text.ParseException;
public class DateTools {
public static Date parse(String formatPattern, String dateString) throws ParseException {
return new SimpleDateFormat(formatPattern).parse(dateString);
}
public static String format(String formatPattern, Date date) {
return new SimpleDateFormat(formatPattern).format(date).toString();
}
}
创建运行类Test.java代码如下:
import java.text.SimpleDateFormat;
public class Test {
public static void main(String[] args) {
//共享变量SimpleDateFormat 导致 java.lang.NumberFormatException: multiple points
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String[] dateStringArray = new String[]{"2000-01-01", "2001-02-02", "2003-03-03", "2004-04-04","2004-04-05","2004-04-06","2004-04-07"};
MyThread[] threadArray = new MyThread[7];
for (int i = 0; i < dateStringArray.length; i++) {
threadArray[i] = new MyThread(sdf, dateStringArray[i]);
}
for (int i = 0; i < dateStringArray.length; i++) {
threadArray[i].start();
}
}
程序运行后的结果是控制台输出空白。
控制台没有输出任何异常,解决处理错误的方法就是创建了多个 SimpleDateFormat 类的实例。
3.解决异常方法 2
ThreadLocal类能使线程绑定到指定的对象。使用该类也可以解决多线程环境下SimpleDateFormat类处理错误的情况。
创建名称为7.4.3项目。
创建MyThread.java类代码如下:
import java.text.ParseException;
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) {
super();
this.sdf = sdf;
this.dateString = dateString;
}
@Override
public void run() {
try {
Date dateRef = DateTools.getSimpleDateFormat("yyyy-MM-dd").parse(dateString);
String newDateString = DateTools.getSimpleDateFormat("yyyy-MM-dd").format(dateRef).toString();
if (!newDateString.equals(dateString)) {
System.out.println("ThreadName= " + this.getName()
+ "报错了 日期字符串: " + dateString + " 转换成的日期为: " + newDateString);
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}
创建类DateTools.java代码如下:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTools {
public static ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<SimpleDateFormat>();
public static SimpleDateFormat getSimpleDateFormat(String datePattern) {
SimpleDateFormat sdf = null;
sdf = t1.get();
if (null == sdf) {
sdf = new SimpleDateFormat(datePattern);
t1.set(sdf);
}
return sdf;
}
}
创建运行类Test.java代码如下:
import java.text.SimpleDateFormat;
public class Test {
public static void main(String[] args) {
//共享变量SimpleDateFormat 导致 java.lang.NumberFormatException: multiple points
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String[] dateStringArray = new String[]{"2000-01-01", "2001-02-02", "2003-03-03", "2004-04-04","2004-04-05","2004-04-06","2004-04-07"};
MyThread[] threadArray = new MyThread[7];
for (int i = 0; i < dateStringArray.length; i++) {
threadArray[i] = new MyThread(sdf, dateStringArray[i]);
}
for (int i = 0; i < dateStringArray.length; i++) {
threadArray[i].start();
}
}
}
程序运行后的结果是控制台输出空白。
控制台没有输出任何异常,没有任何信息被输出,看来运行结果是正确的