SimpleDateFormat经常被声明为static,在并发环境下公用一个实例,由于它不是线程安全的会产生两种问题:1.日期并不是预想的日期,乱七八糟的任何日期都可能出现。 2. 一定几率下抛异常。
所以有人就每次调用格式化都重新new一个SimpleDateFormat实例,这种方式会存在性能问题,因为其实例化是“expensive”的。所以最优的解决方案是采用ThreadLocal方式。代码如下:
<pre name="code" class="java">/** * TheadLocal SimpleDateFormat * Fix SimpleDateFormat concurrency problems and increase performance * * Date date = ConcurrentDateFormat.getInstance("yyyy-MM-dd HH:mm:ss").parse("2015-10-14 15:29:00"); * String dateStr = ConcurrentDateFormat.getInstance("yyyy-MM-dd").format(new Date()); * * @author yuyong.zhao */public class ConcurrentDateFormat { private SimpleDateFormat dateFormat; private Locale locale; private static ThreadLocal<Map<key concurrentdateformat="">> dateFormatThreadLocal = new ThreadLocal<Map<key concurrentdateformat="">>(); private ConcurrentDateFormat(SimpleDateFormat df, Locale locale) { this.dateFormat = df; this.locale = locale; } public String format(Date date) { return dateFormat.format(date); } public String format(Object date) { return dateFormat.format(date); } /** * Returns a <code>String</code> object which formated by * the specified number of milliseconds since the * standard base time known as "the epoch", namely January 1, * 1970, 00:00:00 GMT. * * @param date the milliseconds since January 1, 1970, 00:00:00 GMT. */ public String format(long date) { return dateFormat.format(new Date(date)); } public Date parse(String date) throws ParseException { return dateFormat.parse(date); } /** * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT * represented by this <tt>String</tt> object. * * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT * represented by this string date. */ public long parseToLong(String source) throws ParseException { return parse(source).getTime(); } public static ConcurrentDateFormat getInstance(String pattern) { return getInstance(pattern, TimeZone.getDefault(), Locale.getDefault()); } public static ConcurrentDateFormat getInstance(String pattern, TimeZone timeZone, Locale locale) { if (pattern == null || locale == null) { throw new NullPointerException("Parameter pattern or locale must be not null!"); } Map<key concurrentdateformat=""> formatMap = dateFormatThreadLocal.get(); if (formatMap == null) { formatMap = new HashMap<key concurrentdateformat="">(); dateFormatThreadLocal.set(formatMap); } Key key = new Key(pattern, locale); ConcurrentDateFormat concurrentDateFormat = formatMap.get(key); if (concurrentDateFormat == null) { concurrentDateFormat = new ConcurrentDateFormat(new SimpleDateFormat(pattern, locale), locale); formatMap.put(key, concurrentDateFormat); } concurrentDateFormat.setTimeZone(timeZone); return concurrentDateFormat; } public void setTimeZone(TimeZone timeZone) { this.dateFormat.setTimeZone(timeZone); } public TimeZone getTimeZone() { return this.dateFormat.getTimeZone(); } public Locale getLocale() { return this.locale; } /** * The key for ConcurrentDateFormat * * @author yuyong.zhao */ private static class Key { String pattern; Locale locale; Key(String pattern, Locale locale) { this.pattern = pattern; this.locale = locale; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((locale == null) ? 0 : locale.hashCode()); result = prime * result + ((pattern == null) ? 0 : pattern.hashCode()); return result; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (this == obj) { return true; } if (getClass() != obj.getClass()) { return false; } Key other = (Key) obj; if (locale == null) { if (other.locale != null) { return false; } } else if (!locale.equals(other.locale)) { return false; } if (pattern == null) { if (other.pattern != null) { return false; } } else if (!pattern.equals(other.pattern)) { return false; } return true; } } public static final String YYYY_MM_DD_CN = "yyyy年MM月dd日"; public static final String MM_DD_CN = "MM月dd日"; public static final String YYYY = "yyyy"; public static final String YYYY_MM_DD_HYPHEN = "yyyy-MM-dd"; public static final String YYYY_MM_DD_SLASH = "yyyy/MM/dd"; public static final String HH_MM = "HH:mm"; public static final String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss";}