ThreadLocal和SimpleDateFormat数组

时间:2012-07-07 15:39:06

标签: java thread-safety simpledateformat thread-local

使用与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的情况下?

2 个答案:

答案 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