最近春招开始补基础,才得知SimpleDateFormat不安全的,为啥呢
因为parse(String xx)里面的东西会存储到SimpleDateFormat里面的static Date里面
导致在高并发下,SimpleDateFormat是不安全的。
测试一哈:
public class test implements Runnable {
private String date;
static String[] dateString = {"2017-11-05", "2017-11-06", "2017-11-07", "2017-11-08", "2017-11-09", "2017-11-10", "2017-11-11", "2017-11-12", "2017-11-13", "2017-11-14"};
private SimpleDateFormat simpleDateFormat;
public static void main(String[] args) {
/*ThreadPoolExecutor pool = new ThreadPoolExecutor(
10,
30,
30,
TimeUnit.MINUTES,
new ArrayBlockingQueue<Runnable>(10),
new CustomThreadFactory(),
new CustomRejectedExecutionHandler());*/
ExecutorService pool = Executors.newFixedThreadPool(100);
//SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd");
for (int i = 0; i < dateString.length; i++) {
/*pool.execute(new test("2000-04-28", false));
pool.execute(new test("2018-06-12", true));
pool.execute(new test("2019-02-16", true));
pool.execute(new test("2017-03-24", false));
pool.execute(new test("2020-01-14", false));*/
new Thread(new test(dateString[i])).start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//pool.shutdown();
}
}
@Override
public void run() {
/*if(simpleDateFormat.get()==null){
simpleDateFormat.set(new SimpleDateFormat("yyyy-MM-dd"));
}*/
try {
/*Date todate = tool.getSimpleDateFormat("yyyy-MM-dd").parse(date);
String date1 = tool.getSimpleDateFormat("yyyy-MM-dd").format(todate);*/
Date todate = tool.simpleDateFormat1.parse(date);
String date1 = tool.simpleDateFormat1.format(todate);
if (date.equals(date1)) {
System.out.println("原本输入:" + date + "转换后为:" + date1);
} else {
System.out.println("错误!!!原本输入:" + date + "转换后为:" + date1);
}
} catch (ParseException e) {
//e.printStackTrace();
}
}
public test(String date) {
this.date = date;
}
}
class tool {
public static ThreadLocal<SimpleDateFormat> simpleDateFormat = new ThreadLocal<>();
public static SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd");
public static SimpleDateFormat getSimpleDateFormat(String format) {
SimpleDateFormat sdf = null;
sdf = simpleDateFormat.get();
if (sdf == null) {
sdf = new SimpleDateFormat(format);
simpleDateFormat.set(sdf);
}
return sdf;
}
}
运行结果:
错误!!!原本输入:2017-11-06转换后为:2200-11-05
错误!!!原本输入:2017-11-05转换后为:2200-11-05
原本输入:2017-11-07转换后为:2017-11-07
原本输入:2017-11-08转换后为:2017-11-08
原本输入:2017-11-09转换后为:2017-11-09
原本输入:2017-11-10转换后为:2017-11-10
原本输入:2017-11-11转换后为:2017-11-11
原本输入:2017-11-12转换后为:2017-11-12
原本输入:2017-11-13转换后为:2017-11-13
原本输入:2017-11-14转换后为:2017-11-14
解决方案就是加上ThreadLocal,每个线程都有自己的一份。
public class test implements Runnable {
private String date;
static String[] dateString = {"2017-11-05", "2017-11-06", "2017-11-07", "2017-11-08", "2017-11-09", "2017-11-10", "2017-11-11", "2017-11-12", "2017-11-13", "2017-11-14"};
private SimpleDateFormat simpleDateFormat;
public static void main(String[] args) {
for (int j = 0; j < 100; j++) {
for (int i = 0; i < dateString.length; i++) {
new Thread(new test(dateString[i])).start();
}
}
}
@Override
public void run() {
try {
Date todate = tool.getSimpleDateFormat("yyyy-MM-dd").parse(date);
String date1 = tool.getSimpleDateFormat("yyyy-MM-dd").format(todate);
if (date.equals(date1)) {
System.out.println("原本输入:" + date + "转换后为:" + date1);
} else {
System.out.println("错误!!!原本输入:" + date + "转换后为:" + date1);
}
} catch (ParseException e) {
//e.printStackTrace();
}
}
public test(String date) {
this.date = date;
}
}
class tool {
public static ThreadLocal<SimpleDateFormat> simpleDateFormat = new ThreadLocal<>();
public static SimpleDateFormat simpleDateFormat1=new SimpleDateFormat("yyyy-MM-dd");
public static SimpleDateFormat getSimpleDateFormat(String format) {
SimpleDateFormat sdf = null;
sdf = simpleDateFormat.get();
if (sdf == null) {
sdf = new SimpleDateFormat(format);
simpleDateFormat.set(sdf);
}
return sdf;
}
}
输出就正常了