我收到查找错误错误 - 调用静态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);
答案 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。
日期格式未同步。它 建议单独创建 每个线程的格式实例。如果 多个线程访问一种格式 同时,它必须同步 外部
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的示例:
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的所有引用来解决这个问题 - 只需确保所有调用都包含在相同的同步对象中!