使用与recent question中描述的模式非常相似的模式,对于多线程应用程序,我得到了奇怪的日期值(例如2025年或2035年,当源数据中显然没有这样的值时) 。似乎发生了并发问题。
源代码看起来像
// Various Java DateFormat patterns, e.g. "yyyy-MM-dd".
private static final String[] DATE_PATTERNS = new String[] {...};
private static SimpleDateFormat[] getFormats(final String[] patterns)
{
ThreadLocal<SimpleDateFormat[]> LOCAL_FORMATS = new ThreadLocal<SimpleDateFormat[]>()
{
@Override
protected SimpleDateFormat[] initialValue()
{
List<SimpleDateFormat> formatList = new ArrayList<SimpleDateFormat>();
for (String pattern:patterns)
{
formatList.add(new SimpleDateFormat(pattern));
}
return formatList.toArray(new SimpleDateFormat[formatList.size()]);
}
};
return LOCAL_FORMATS.get(); // Create a thread-local copy
}
private static final SimpleDateFormat[] DATE_FORMATS = getFormats(DATE_PATTERNS);
在静态初始化之后,DATE_FORMATS
数组被许多类访问,而这些类又使用数组的SimpleDateFormat
个对象来解析或格式化多个日期字符串。
在这种使用场景中是否会出现任何并发问题,尤其是在使用ThreadLocal
的情况下?
答案 0 :(得分:4)
是的,可能存在并发问题。您的线程局部变量不起任何作用。它仅在初始化类时使用,以临时存储立即检索并存储在静态常量中的日期格式数组。
之后的所有线程总是同时使用相同的日期格式实例,而不从任何线程局部变量中获取它们。
代码应该是:
private static final String[] DATE_PATTERNS = new String[] {...};
private static final ThreadLocal<SimpleDateFormat[]> DATE_FORMATS =
new ThreadLocal<SimpleDateFormat[]>() {
@Override
protected SimpleDateFormat[] initialValue() {
List<SimpleDateFormat> formatList = new ArrayList<SimpleDateFormat>();
for (String pattern : DATE_PATTERNS)
{
formatList.add(new SimpleDateFormat(pattern));
}
return formatList.toArray(new SimpleDateFormat[formatList.size()]);
}
};
public static SimpleDateFormat[] getDateFormats() {
return DATE_FORMATS.get();
}
我还会使用不可修改的List<SimpleDateFormat>
而不是数组,以便更安全。
答案 1 :(得分:2)
// Various Java DateFormat patterns, e.g. "yyyy-mm-dd".
格式'yyyy-mm-dd'可能会给你带来奇怪的结果,因为'mm'是几分钟而不是几个月。来自javadoc:
M Month in year Month July; Jul; 07
...
m Minute in hour Number 30