回覆列表
  • 1 # 讀樂樂傳送門

    Java 文件有關 SimpleDateFormat 的描述:

    “日期格式是非同步的。

    建議為每個執行緒建立單獨的日期格式化例項。

    如果多個執行緒併發訪問某個格式化例項,則必須保證外部呼叫同步性。“

    正如文件中提到的那樣,可以為每個執行緒設定不同例項來解決這個問題。如果要共享例項,該如何實現?

    1. ThreadLocal

    可以使用 ThreadLocal 解決。Threadlocal 的 get() 方法會給當前執行緒提供正確的值。

    2.JDK 8 新API

    Java8 引入了新的日期時間 API,SimpleDateFormat 有了更好的替代者。如果繼續堅持使用 SimpleDateFormat 可以配合 ThreadLocal 一起使用。但既然已經有了更好的選擇,還是考慮用新的 API。

    Java 8 提供了幾個執行緒安全的日期類,Java 文件中這麼描述:

    “這個類是具有不可變和執行緒安全的特點。”

    非常值得學習這些類的用法,包括 DateTimeFormatter、OffsetDateTime、ZonedDateTime、LocalDateTime、LocalDate 和 LocalTime。

  • 2 # 都市心聲

    為什麼使用Java的SimpleDateFormat偶爾出現值不正確的情況?

    雖然沒有具體描述在什麼情況下會偶爾出現值不正確的情況,不過我可以預測一下應該是在多執行緒的情況下出現的,那麼為什麼說在多執行緒的情況下會出現呢,對此,我們可以檢視一下SimpleDateFormat的原始碼,發現作者有一段註釋如下:

    我們可以看到原來SimpleDateFormat並不是執行緒安全的,作者推薦為每一個執行緒建立一個單獨的例項,或者為SimpleDateFormat加鎖。

    其實到了JDK1.8後,我們完全可以不用SimpleDateFormat了,可以用它新加入的類

    java.time.format.DateTimeFormatter

    ,完美地解決了SimpleDateFormat的多執行緒安全問題,它使用instant代替Date,LocalDateTime替代Calendar,不過得改動老程式碼了,對不想改動的程式設計師來說有點難受,如果還是想繼續用SimpleDateFormat的話,那我們就把它用ThreadLocal包裝一下,如下所示:

    有類似問題的朋友可以動手操作一下,建議還是用DateTimeFormatter,因為包裝之後的代價也還是蠻大的。

  • 3 # 程式猿W

    我將從以下幾點進行說明:

    1、SimpleDateFormat的使用

    2、為什麼SimpleDateFormat執行緒不安全呢?

    3、怎樣解決SimpleDateFormat的執行緒不安全物件

    4、總結

    SimpleDateFormat的使用

    我們通常都會寫一個日期處理工具類DateUtils,使用時直接使用這個例項來進行操作。程式碼如下:

    那麼怎麼使用呢?

    DateUtils.parseString("2020-05-01 10:02:02")

    上述程式碼的呼叫,在大部分的時間裡都會工作的很好,但是當你的專案併發比較高的時候,問題就出來了,比如轉化的時間不正確,比如報錯,執行緒掛死。我們看下下面案例:

    執行輸入如下:

    報java.lang.NumberFormatException: multiple points錯誤,直接掛死,沒起來;

    還有下面問題:我們只是解析 2020-05-01 10:02:02,下面輸出結果卻是各種各樣的結果。

    為什麼SimpleDateFormat執行緒不安全呢?

    我們先按下JDK中是怎樣介紹SimpleDateFormat類的。

    Date formats are not synchronized.

    * It is recommended to create separate format instances for each thread.

    * If multiple threads access a format concurrently, it must be synchronized

    Date formats 是執行緒不安全的。推薦為每個執行緒建立單獨的format例項。如果多執行緒併發訪問同一個format例項,必須加同步操作。

    那下面我們分析原始碼來說明為什麼執行緒不安全?

    因為我們在工具類中把SimpleDateFormat定義為靜態變數,那麼在多執行緒環境下SimpleDateFormat就會被多執行緒共享,B執行緒會讀取到A執行緒的時間,就會出現時間差異和其他問題。

    那我們來看parse做了什麼?

    從上面程式碼看(3)(4)(5) 操作不是原子性,當多個執行緒呼叫parse方法適合,比如A執行了(3)(4),也就是設定了cal物件,在執行程式碼(5) 前執行緒B 執行了程式碼(3) 清空了cal物件,由於多個執行緒使用的是一個cal物件,所以執行緒A執行(5) 的時候返回的是被執行緒B清空後的物件

    怎樣解決SimpleDateFormat的執行緒不安全物件

    (1) 每次使用時new一個SimpleDateFormat 的 例項,這樣可以保證每個例項使用自己的Calendar例項,但是每次使用都需要new一個物件,並且使用後由於沒有其他引用,又需要回收,開銷會很大。

    (2) 可以使用synchronized 對SimpleDtaFormat例項進行同步

    (3) 使用ThreadLocal,這樣每個執行緒只需要使用一個SimpleDateFormate例項,這相比第一種方式 節省了物件的建立銷燬開銷,並且不需要使多個執行緒同步。

    (4) 使用JDK8中的 DateTimeFormatter

    上面說明此類是執行緒安全的。

    總結

    SimpleDateFormat 是執行緒不安全的類,一般不要定義為 static 變數,如果定義為 static ,

    必須加鎖,或者使用 DateUtils 工具類。

    正例:注意執行緒安全,使用 DateUtils。亦推薦如下處理:

    說明:如果是 JDK8 的應用,可以使用 Instant 代替 Date,LocalDateTime 代替 Calendar,

    DateTimeFormatter 代替 SimpleDateFormat,官方給出的解釋:simple beautiful strong immutable thread-safe。

  • 中秋節和大豐收的關聯?
  • 快手祁天道,真名孟凡斌,和他老婆構成詐騙罪,你們怎麼看?