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

时间:2010-03-09 14:24:53

标签: java static

我收到查找错误错误 - 调用静态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);

8 个答案:

答案 0 :(得分:79)

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 documentation说:

  

正如JavaDoc所述,DateFormats是   多线程本质上不安全   使用。探测器找到了一个电话   具有的DateFormat实例   是通过静态场获得的。这个   看起来很可疑。

     

有关此内容的更多信息,请参阅Sun.   Bug#6231579和Sun Bug#6178997。

javadoc for DateFormat建议:

  

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

Jack Leow's answer对静态使用“TODAY”的语义也有一个很好的观点。

顺便说一句,我实际上已经看到这种情况发生在高流量的生产环境中,最初调试是一件非常混乱的事情;所以根据我的经验,FindBugs警告实际上是一个有用的建议(不像其他一些静态分析规则,有时候看起来很挑剔)。

答案 1 :(得分:15)

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

答案 2 :(得分:4)

你确定它不是

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

?这就是错误消息所指示的内容。

我认为它的目的是DateFormat不是线程安全的,因此将实例作为静态字段表示潜在的竞争条件。

答案 3 :(得分:4)

我不确定FindBugs是否在抱怨这个问题,但我在代码中看到的一个问题是你将TODAY定义为类级别(静态),常量(最终)变量。这传达了你希望TODAY永远不会改变的意图(我不相信这种情况,因为java.util.Dates是可变的,但这是另一个故事)。

考虑如果应用程序运行多天会发生什么? TODAY(除非您更新它)将引用应用程序启动的那一天,而不是当前日期。你确定这就是你的意思吗?

这可能不是你代码中的错误,但目的不明确,我相信可能是FindBugs所抱怨的。

答案 4 :(得分:3)

未提及的替代方法是使用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 )

答案 5 :(得分:0)

一方面,这不是线程安全的。

答案 6 :(得分:0)

我认为这是因为格式不是线程安全的吗?

(我还没有看到什么蠢货抱怨,你能提供吗? 警告文本?)

答案 7 :(得分:0)

你可以通过在同步块中包含对DateFormat的所有引用来解决这个问题 - 只需确保所有调用都包含在相同的同步对象中!