格式化时间常用的就是SimpleDateFormat这个类了,然而这样的写法在单线程程序中不会出现线程不安全的问题,但是在多线程的环境下却会出现线程不安全的问题。
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static Date formatDate(String date) throws ParseException {
return simpleDateFormat.parse(date);
}
在多线程下环境下使用这个方法进行时间的格式化,看下执行结果是否都一致。
//当在单线程的程序中调用formatDate(String date),此时并不会出现任何问题。然而当程序在多线程并发执行调用这个方法的时候
//就会产生线程不安全的问题
private static final ExecutorService executorService = Executors.newFixedThreadPool(5);
public static void main(String[] args) {
final int threadCount = 1000;
for (int i = 0; i < threadCount; i++) {
Runnable runnable = () -> {
try {
System.out.println(formatDate("2020-03-30 08:08:08"));
} catch (ParseException e) {
e.printStackTrace();
}
};
executorService.submit(runnable);
}
executorService.shutdown();
}
执行结果如下:
Mon Mar 30 08:08:08 CST 2020
Mon Mar 30 08:08:08 CST 2020
Mon Mar 30 08:08:08 CST 2020
Mon Mar 30 08:08:08 CST 2020
Sun Mar 30 08:08:08 CST 20220200
Mon Mar 30 08:08:08 CST 2020
Mon Mar 30 08:08:08 CST 2020
Mon Mar 30 08:08:08 CST 2020
我们可以看到多次执行其结果不一致,为什么会出现这种情况呢?从SimpleDateFormat.parse()源码可以看到,在多线程环境下,在calendar进行操作时,后面的线程有可能会覆盖上一个线程设置好的值,这就导致了线程不安全的问题存在。
解决之道!!!
使用ThreadLocal进行避免,这样每个线程中返回各自的实例,避免了多线程环境下共用一个实例导致线程不安全的问题。
private static SimpleDateFormat getSimpleDateFormate() {
SimpleDateFormat simpleDateFormat = threadLocal.get();
if (simpleDateFormat == null) {
simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
threadLocal.set(simpleDateFormat);
}
return simpleDateFormat;
}
public static void remove() {
threadLocal.remove();
}
private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static LocalDateTime dateTimeFormatter(String date) {
return LocalDateTime.parse(date, dateTimeFormatter);
}
private static final ExecutorService executorService = Executors.newFixedThreadPool(5);
public static void main(String[] args) {
final int threadCount = 1000;
for (int i = 0; i < threadCount; i++) {
Runnable runnable = () -> {
try {
System.out.println(formatDateWithSecurity("2020-03-30 08:08:08"));
remove();
} catch (ParseException e) {
e.printStackTrace();
}
};
executorService.submit(runnable);
}
executorService.shutdown();
}
解决之道二!!!
使用java8提供的DateTimeFormatter进行日期的格式化。
private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static LocalDateTime dateTimeFormatter(String date) {
return LocalDateTime.parse(date, dateTimeFormatter);
}
private static final ExecutorService executorService = Executors.newFixedThreadPool(5);
public static void main(String[] args) {
final int threadCount = 1000;
for (int i = 0; i < threadCount; i++) {
Runnable runnable = () -> {
System.out.println(dateTimeFormatter("2020-03-30 08:08:08"));
};
executorService.submit(runnable);
}
executorService.shutdown();
}
以上就是关于讲述SimpleDateFormate在多线程下不安全的问题和如何解决的方法。