ThreadLocal and SimpleDateFormat array

廉价感情. 提交于 2019-12-10 18:02:57

问题


Using a pattern very similar to that described in a recent question, for a multithreaded application, I am getting weird date values (e.g., years like 2025 or 2035, when clearly no such value exists in the source data). It seems that a concurrency issue is occuring.

The source code looks something like

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

After its static initialization, the DATE_FORMATS array is accessed by numerous classes, which in turn use the SimpleDateFormat objects of the array for parsing or formatting several date strings.

Can there be any concurrency issue in such a usage scenario, especially given the use of ThreadLocal?


回答1:


Yes, there can be concurrency issues. Your thread local variable doesn't serve any purpose. It's only used when the class is initialized, to temporarily store an array of date formats that is immediately retrieved and stored in a static constant.

All the threads, after, always use the same instances of date formats concurrently, without getting them from any thread local variable.

The code should rather be:

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

I would also use an unmodifiable List<SimpleDateFormat> rather than an array, to be safer.




回答2:


// Various Java DateFormat patterns, e.g. "yyyy-mm-dd".

The format 'yyyy-mm-dd' is likely to give you weird results because 'mm' is minutes and not months. From the javadoc:

M   Month in year   Month   July; Jul; 07
...
m   Minute in hour  Number  30


来源:https://stackoverflow.com/questions/11376328/threadlocal-and-simpledateformat-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!