簡體   English   中英

調用靜態java.text.DateFormat的方法不可取嗎?

[英]Call to method of static java.text.DateFormat not advisable?

我收到一個Find Bugs錯誤 - 調用靜態java.text.DateFormat的方法,我不知道為什么在下面做這些事情不好/可取的原因。

private static final Date TODAY = Calendar.getInstance().getTime();
private static final DateFormat yymmdd = new SimpleDateFormat("yyMMdd"); 

private String fileName = "file_" + yymmdd.format(TODAY);

DateFormats不是線程安全的,這意味着它們維護狀態的內部表示。 如果多個線程同時訪問同一個實例,在靜態上下文中使用它們會產生一些非常奇怪的錯誤。

我的建議是將變量置於您使用它們的位置,而不是使它們成為類的靜態屬性。 在初始化類時,您可能正在執行此操作,因此您可以在構造函數中執行此操作:

public class MyClass {
    private String fileName;

    public MyClass() {
        final Date today = Calendar.getInstance().getTime();
        final DateFormat yymmdd = new SimpleDateFormat("yyMMdd"); 

        this.fileName = "file_" + yymmdd.format(TODAY);
    }
    ...
}

如果你需要在多個地方使用格式化程序,你可能只需要將模式設置為static final並在需要時創建一個新的本地DateFormat

public class MyClass {
    private static final String FILENAME_DATE_PATTERN = "yyMMdd";

    public void myMethod() {
        final DateFormat format = new SimpleDateFormat(FILENAME_DATE_PATTERN);
        // do some formatting
    }
}

該問題的FindBugs文檔說:

正如JavaDoc所述,DateFormats對於多線程使用本質上是不安全的。 檢測器找到了一個通過靜態字段獲得的DateFormat實例的調用。 這看起來很可疑。

有關這方面的更多信息,請參閱Sun Bug#6231579和Sun Bug#6178997。

DateFormatjavadoc建議:

日期格式未同步。 建議為每個線程創建單獨的格式實例。 如果多個線程同時訪問格式,則必須在外部進行同步。

Jack Leow的答案對於靜態使用“TODAY”的語義也有一個很好的觀點。

另外,我實際上已經看到這種情況發生在高流量的生產環境中,最初調試是一件非常令人困惑的事情。 所以根據我的經驗,FindBugs警告實際上是一個有用的建議(不像其他一些靜態分析規則,有時似乎是挑剔的)。

Commons Lang有一個線程安全的FastDateFormat對象。 它只進行格式化,而不是解析。

如果你可以使用commons-lang,這可能適合你。

private static final Date TODAY = Calendar.getInstance().getTime();
private static final FastDateFormat yymmdd = FastDateFormat.getInstance("yyMMdd");

private String fileName = "file_" + yymmdd.format(TODAY);

你確定不是嗎?

private static final DateFormat yymmdd = new SimpleDateFormat("yyMMdd"); 

這就是錯誤消息所指示的內容。

我認為它的目的是DateFormat不是線程安全的,因此將實例作為靜態字段表示潛在的競爭條件。

我不確定FindBugs是否在抱怨這個,但我看到你的代碼中的一個問題是你將TODAY定義為類級別(靜態),常量(最終)變量。 這傳達了你希望TODAY永遠不會改變的意圖(我不相信這種情況,因為java.util.Dates是可變的,但這是另一個故事)。

想想如果你的應用程序運行多天會發生什么? TODAY (除非您更新它)將引用應用程序啟動的那一天,而不是當前日期。 你確定這就是你的意思嗎?

這可能不是你的代碼中的錯誤,但目的不明確,我相信這可能是FindBugs抱怨的。

沒有提到的替代方法是使用ThreadLocal。 有關3個選項之間的更多信息+性能比較,請參見http://www.javacodegeeks.com/2010/07/java-best-practices-dateformat-in.html

  • 每次創建一個實例
  • 同步訪問
  • 使用ThreadLocal

使用ThreadLocal的示例:

private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
    @Override
    protected SimpleDateFormat initialValue() {
        return new SimpleDateFormat("yyMMdd");
    }
};

用法:

DATE_FORMAT.get().format( TODAY )

一方面,這不是線程安全的。

我認為這是因為格式不是線程安全的?

(我還沒有看到findbugs抱怨什么,你能提供警告文字嗎?)

你可以通過在同步塊中包裝對DateFormat的所有引用來解決這個問題 - 只需確保所有調用都包含在同一個同步對象中!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM