首頁 > 軟體

Java SimpleDateFormat執行緒不安全問題

2023-03-25 06:02:14

多執行緒 ——SimpleDateFormat

public class DateTest {
    //工具類中的日期元件
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    public static void main(String[] args) throws Exception {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(10));
        for (int i = 0; i < 100; i++) {
            threadPoolExecutor.execute(() -> {
                String dateString = sdf.format(new Date());
                try {
                    Date parseDate = sdf.parse(dateString);
                    String dateString2 = sdf.format(parseDate);
                    System.out.println(dateString.equals(dateString2));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    }
}

結果

原因分析

全域性變數的SimpleDateFormat,在並行情況下,存在安全性問題。

我們通過原始碼看下:

SimpleDateFormat繼承了 DateFormat

DateFormat類中維護了一個全域性的Calendar變數

sdf.parse(dateStr)和sdf.format(date),都是由Calendar參照來儲存的。

如果SimpleDateFormat是static全域性共用的,Calendar參照也會被共用。

又因為Calendar內部並沒有執行緒安全機制,所以全域性共用的SimpleDateFormat不是線性安全的。

解決方法

解決方法1

「FastDateFormat(FastDateFormat能保證執行緒安全) 替換 SimpleDateFormat」

private static final FastDateFormat sdf = FastDateFormat.getInstance(“yyyy-MM-dd HH:mm:ss”);

 測試程式碼如下所示:

public class DateTest {
    //工具類中的日期元件
//    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private static final FastDateFormat sdf = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) throws Exception {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(10));
        for (int i = 0; i < 100; i++) {
            threadPoolExecutor.execute(() -> {
                String dateString = sdf.format(new Date());
                try {
                    Date parseDate = sdf.parse(dateString);
                    String dateString2 = sdf.format(parseDate);
                    System.out.println(dateString.equals(dateString2));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
        threadPoolExecutor.shutdown();
    }
}

列印結果:

解決方法2

「使用DateTimeFormatter(DateTimeFormatter是執行緒安全的,java 8+支援)代替SimpleDateFormat」

private static DateTimeFormatter sdf = DateTimeFormatter.ofPattern(“yyyy-MM-dd HH:mm:ss”);

測試程式碼如下:

public class DateTest {
//工具類中的日期元件
// private static final SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
private static DateTimeFormatter sdf = DateTimeFormatter.ofPattern(“yyyy-MM-dd HH:mm:ss”);

// private static final FastDateFormat sdf = FastDateFormat.getInstance(“yyyy-MM-dd HH:mm:ss”);

public static void main(String[] args) throws Exception {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(10));
    for (int i = 0; i < 100; i++) {
        threadPoolExecutor.execute(() -> {
            try {
                String dateString = sdf.format(LocalDateTime.now());
                TemporalAccessor temporalAccessor = sdf.parse(dateString);
                String dateString2 = sdf.format(temporalAccessor);
                System.out.println(dateString.equals(dateString2));
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
    threadPoolExecutor.shutdown();
}

}
列印結果如下:

總結

在多執行緒中使用全域性變數時一定要考慮到執行緒安全問題,若不確定是否存線上程安全問題的公共變數,則不要冒然使用,可以做一些測試和資料分析,或者使用區域性變數。

到此這篇關於Java SimpleDateFormat執行緒不安全問題的文章就介紹到這了,更多相關SimpleDateFormat執行緒不安全內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com