前言: 类SimpleDateFormat 主要负责日期的转换与格式化但是在多线程环境中使用此类容易造成数据转换及处理不准确,因为SimpleDateFormat 类并不是线程安全的。
- 模拟多线程使用出现问题
1、线程类
package com.dairuijie.date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
* @ClassName: DateThread
* @Description:TODO(模擬多線程)
* @author: drj
* @date: 2019年9月22日 下午4:40:01
*
* @Copyright: 2019
*
*/
public class DateThread extends Thread {
private String dateString;
private SimpleDateFormat sdf;
private String formatPattren = "yyyy-MM-dd";
public DateThread(String dateString, SimpleDateFormat sdf) {
super();
this.dateString = dateString;
this.sdf = sdf;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
Date date = sdf.parse(dateString);
String newDate = sdf.format(date);
System.out.println("ThreadName---" + this.getName() + "-----dateString-" + dateString + "newDate-" + newDate);
if (!dateString.equals(newDate)) {
System.err.println("报错了");
}
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.run();
}
}
2、主方法
package com.dairuijie.date;
import java.text.SimpleDateFormat;
public class Test {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String[] s = new String[] {"2019-09-22","2019-09-29","2019-09-09",
"2019-09-01","2019-09-03","2019-09-08",
"2019-09-02","2019-09-04","2019-09-21",
"2019-09-07","2019-09-06","2019-09-05",
"2019-09-08","2019-09-09","2019-09-10",
"2019-09-11","2019-09-12","2019-09-13","2019-09-14",
"2019-09-12","2019-09-14","2019-09-16",
"2019-09-18","2019-09-17"};
DateThread[] threads = new DateThread[s.length];
for(int i=0; i < s.length; i++) {
threads[i] = new DateThread(s[i], sdf);
}
for(int i=0; i < s.length; i++) {
threads[i].start();
}
}
}
3、运行结果
通过上面代码可以发现在多线程情况下出现转换异常问题,解决问题有两种方案。
方案一 每次new SimpleDateformat 方案二使用ThreadLocal 局部线程对象。
- 方案一每次new SimpleDateformat
1、新建工具类
package com.dairuijie.date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
* @ClassName: DateTools
* @Description:TODO(日期工具类)
* @author: drj
* @date: 2019年9月22日 下午4:01:30
*
* @Copyright: 2019
*
*/
public class DateTools {
private static ThreadLocal<SimpleDateFormat> local = new ThreadLocal<SimpleDateFormat>();
public static Date parse(String formatPattren, String dateString) throws ParseException {
return new SimpleDateFormat(formatPattren).parse(dateString);
}
public static String format(String formatPattren, Date date) {
return new SimpleDateFormat(formatPattren).format(date).toString();
}
}
2、重写线程获取方法
package com.dairuijie.date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
* @ClassName: DateThread
* @Description:TODO(模擬多線程)
* @author: drj
* @date: 2019年9月22日 下午4:40:01
*
* @Copyright: 2019
*
*/
public class DateThread extends Thread {
private String dateString;
private SimpleDateFormat sdf;
private String formatPattren = "yyyy-MM-dd";
public DateThread(String dateString, SimpleDateFormat sdf) {
super();
this.dateString = dateString;
this.sdf = sdf;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
Date date = DateTools.parse("yyyy-MM-dd", dateString);
String newDate = DateTools.format(formatPattren, date);
System.out.println("ThreadName---" + this.getName() + "-----dateString-" + dateString + "newDate-" + newDate);
if (!dateString.equals(newDate)) {
System.err.println("报错了");
}
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.run();
}
}
- 方案二 使用ThreadLocal
package com.dairuijie.date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
* @ClassName: DateTools
* @Description:TODO(日期工具类)
* @author: drj
* @date: 2019年9月22日 下午4:01:30
*
* @Copyright: 2019
*
*/
public class DateTools {
private static ThreadLocal<SimpleDateFormat> local = new ThreadLocal<SimpleDateFormat>();
public static Date parse(String formatPattren, String dateString) throws ParseException {
return new SimpleDateFormat(formatPattren).parse(dateString);
}
public static String format(String formatPattren, Date date) {
return new SimpleDateFormat(formatPattren).format(date).toString();
}
public static SimpleDateFormat getSimpleDateFormat(String pattern) {
SimpleDateFormat sdf = null;
sdf = local.get();
if(sdf == null) {
sdf = new SimpleDateFormat(pattern);
local.set(sdf);
}
return sdf;
}
}
package com.dairuijie.date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
* @ClassName: DateThread
* @Description:TODO(模擬多線程)
* @author: drj
* @date: 2019年9月22日 下午4:40:01
*
* @Copyright: 2019
*
*/
public class DateThread extends Thread {
private String dateString;
private SimpleDateFormat sdf;
private String formatPattren = "yyyy-MM-dd";
public DateThread(String dateString, SimpleDateFormat sdf) {
super();
this.dateString = dateString;
this.sdf = sdf;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
Date date = DateTools.getSimpleDateFormat(formatPattren).parse(dateString);
String newDate = DateTools.getSimpleDateFormat(formatPattren).format(date);
System.out.println("ThreadName---" + this.getName() + "-----dateString-" + dateString + "newDate-" + newDate);
if (!dateString.equals(newDate)) {
System.err.println("报错了");
}
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.run();
}
}
- 方案一和二的结果一直没有问题
- 总结
方案一适用一般场景 对于性能要求高并发频繁的使用方案二。