1 单线程环境
类SimpleDateFormate常用于时间格式转换,在单线程环境下运行结果正常,如下所示
public class MyThread extends Thread {
private SimpleDateFormatsdf;
private StringdateString;
publicMyThread(SimpleDateFormatsdf, String dateString) {
this.sdf =sdf;
this.dateString =dateString;
}
Public void run() {
try {
Date date = sdf.parse(dateString);
String newDateString = sdf.format(date).toString();
if (!newDateString.equals(dateString)) {
System.out.println("日期字符串: " + dateString + "转换成日期为:" +newDateString);
}
} catch(ParseExceptione) {
e.printStackTrace();
}
}
}
public class SingleThreadTest{
public static void main(String[]args) {
SimpleDateFormat sdf = newSimpleDateFormat("yyyy-MM-dd");
String[] dateStringArray = new String[]{"2017-01-01","2017-01-02", "2017-01-03","2017-01-04", "2000-01-05",
"2017-01-06", "2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10"};
MyThread[] threadArray = newMyThread[10];
for(inti = 0; i < 10;i++){
threadArray[i] = new MyThread(sdf,dateStringArray[i]);
}
for(inti = 0; i < 10;i++){
threadArray[i].run(); //单线程情况下
}
}
}
运行结果:
2 并发环境
在并发环境下,使用类SimpleDateFormate进行日期格式转换会出现数据处理不正确,根本原因是存在共享变量calendar。
public class MutiThreadTest{
public static void main(String[]args) {
SimpleDateFormat sdf = newSimpleDateFormat("yyyy-MM-dd");
String[] dateStringArray = new String[]{"2017-01-01","2017-01-02", "2017-01-03","2017-01-04", "2000-01-05",
"2017-01-06", "2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10"};
MyThread[] threadArray = newMyThread[10];
for(inti = 0; i < 10;i++){
threadArray[i] = new MyThread(sdf,dateStringArray[i]);
}
for(inti = 0; i < 10;i++){
threadArray[i].start(); //多线程条件下
}
}
}
运行结果:
3 解决方法
3.1使用 LocalDate类
JDK8时间新特性类LocalDate是线程安全,而且使用方法更简单
public class Test {
public static void main(String[]args) {
String[] dateStringArray = new String[]{"2017-01-01","2017-01-02", "2017-01-03","2017-01-04", "2000-01-05",
"2017-01-06", "2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10"};
MyThread[] threadArray = newMyThread[10];
for(inti = 0; i < 10;i++){
threadArray[i] = new MyThread(dateStringArray[i]);
}
for(inti = 0; i < 10;i++){
threadArray[i].start(); //多线程条件下
}
}
}
public class MyThread extends Thread {
private StringdateString;
public MyThread(StringdateString) {
super();
this.dateString =dateString;
}
public void run() {
LocalDate date = LocalDate.parse(dateString);// JDK8新特性
if (!date.toString().equals(dateString)) {
System.out.println("日期字符串: " +dateString + "转换成日期为:" +date);
}
}
}
3.2 使用ThreadLocal类
类ThreadLocal解决的是变量在不同线程间的隔离性,也就是不同线程拥有自己的隔离值,不同线程中的值可以放入ThreadLocal类中进行保存。
public class DateTools{
privatestaticThreadLocal<SimpleDateFormat> t1 = newThreadLocal<SimpleDateFormat>();
publicstaticSimpleDateFormat getSimpleDateFormate(StringdatePattern){
SimpleDateFormat sdf = null;
sdf = t1.get();
if(sdf ==null){
sdf = newSimpleDateFormat(datePattern);
t1.set(sdf);
}
returnsdf;
}
}
public class MyThread extends Thread {
private StringdateString;
public MyThread(StringdateString) {
super();
this.dateString =dateString;
}
publicvoid run(){
try {
Date dateRef =DateTools.getSimpleDateFormate("yyyy-MM-dd").parse(dateString);
String newDateString = DateTools.getSimpleDateFormate("yyyy-MM-dd").format(dateRef).toString();
if (!newDateString.equals(dateString)) {
System.out.println("日期字符串: " + dateString + "转换成日期为:" +newDateString);
}
} catch(ParseExceptione) {
e.printStackTrace();
}
}
}
public class Test {
publicstatic voidmain(String[]args) {
String[] dateStringArray = new String[]{"2017-01-01","2017-01-02", "2017-01-03","2017-01-04", "2000-01-05",
"2017-01-06", "2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10"};
MyThread[] threadArray = newMyThread[10];
for(inti = 0; i < 10;i++){
threadArray[i] = newMyThread(dateStringArray[i]);
}
for(inti = 0; i < 10;i++){
threadArray[i].start(); //多线程条件下
}
}
}
4 参考文献
[1] 高洪岩, Java多线程编程核心技术. 2015.
[2] Goetz, B.等, Java 并发编程实战. 2012.
[3] https://docs.oracle.com/javase/8/docs/api/index.html