调用静态java.text.DateFormat的方法不可取?

2022-08-31 21:11:13

我收到一个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);

答案 1

DateFormat 不是线程安全的,这意味着它们维护状态的内部表示形式。在静态上下文中使用它们可能会产生一些非常奇怪的错误,如果多个线程同时访问同一实例。

我的建议是使变量成为你使用它们的位置的局部变量,而不是使它们成为类的静态属性。看起来在初始化类时可能会执行此操作,因此您可以在构造函数中执行此操作:

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 finalDateFormat

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所述,DateFormat对于多线程使用本质上是不安全的。检测器发现了对 DateFormat 实例的调用,该调用是通过静态字段获得的。这看起来很可疑。

有关这方面的更多信息,请参阅 Sun Bug #6231579 和 Sun Bug #6178997。

DateFormat的javadoc建议:

日期格式不同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问一种格式,则必须在外部同步该格式。

Jack Leow的答案对你静态使用“TODAY”的语义也有一个很好的观点。

顺便说一句,我实际上已经在高流量生产环境中看到了这种情况,起初调试是一件非常令人困惑的事情。因此,根据我的经验,FindBugs警告实际上是一个有用的建议(与其他一些静态分析规则不同,这些规则有时似乎很挑剔)。


答案 2

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);

推荐