一般情況下:
在日常開發中,我們會把SimpleDateFormat定義爲一個靜態變量,以此來避免頻繁創建對象實例,但是在多線程的情況下,SimpleDateFormat實例就會被多個線程共享,會出現各種各樣的問題。
解決方案:
1、使用synchronized,非常簡單的解決了線程安全的問題,缺陷就是synchronized是重量級的,併發量大的時候對性能有影響。
2、在需要的時候創建新的實例,不用static修飾
public static String formatDate(Date date) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(date);
}
public static Date parse(String strDate) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.parse(strDate);
}
如上代碼,僅在需要用到的地方創建一個新的實例,就沒有線程安全問題,不過也加重了創建對象的負擔,會頻繁地創建和銷燬對象,效率較低。
3、使用ThreadLocal
private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
public static Date parse(String dateStr) throws ParseException {
return threadLocal.get().parse(dateStr);
}
public static String format(Date date) {
return threadLocal.get().format(date);
}
ThreadLocal可以確保每個線程都可以得到單獨的一個SimpleDateFormat的對象,那麼自然也就不存在競爭問題了。
4、基於JDK1.8的DateTimeFormatter
在jdk1.8中,可以使用instant代替Date,LocalDateTime 代替 Calendar,DateTimeFormatter代替simpleDateFormat,
public class SimpleDateFormatTest {
//DateTimeFormatter的類是不可變的,並且是線程安全的。
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public static String formatDate(LocalDateTime date) {
return formatter.format(date);
}
public static LocalDateTime parse(String dateNow) {
return LocalDateTime.parse(dateNow, formatter);
}
public static void main(String[] args) throws Exception {
//創建線程池
ExecutorService service = Executors.newFixedThreadPool(50);
// 20個線程
for (int i = 0; i < 20; i++) {
service.execute(() -> {
for (int j = 0; j < 10; j++) {
try {
System.out.println(parse(formatDate(LocalDateTime.now())));
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
service.shutdown();
service.awaitTermination(1, TimeUnit.DAYS);
}
}
阿里開發手冊中:
private static final ThreadLocal<DateFormat> sdf = new ThreadLocal<DateFormat>(){
@override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
}