java时间格式化(线程安全的时间格式化FastDateFormat)
java时间格式化(线程安全的时间格式化FastDateFormat)private static final FormatCache<FastDateFormat> cache= new FormatCache<FastDateFormat>() { @Override protected FastDateFormat createInstance(final String pattern final TimeZone timeZone final Locale locale) { return new FastDateFormat(pattern timeZone locale); } }; public static FastDateFormat getInstance(final String pattern) { return

大家都知道SimpleDateFormat是线程不安全的
protected Calendar calendar;
    
SimpleDateFormat中的calendar是成员变量,同实例多个线程下会共享该calendar对象
而在进行格式化的时候可能会由于第一个线程还没有格式化完成,而第二个线程已经将时间修改了的情况
private StringBuffer format(Date date  StringBuffer toAppendTo 
                                FieldDelegate delegate) {
        // 如果第一个线程设置了时间之后还没有格式化为字符串,此时第二个线程将时间覆盖掉,就会出现线程安全问题
        calendar.setTime(date);
        boolean useDateFormatSymbols = useDateFormatSymbols();
        for (int i = 0; i < compiledpattern.length; ) {
            int tag = compiledPattern[i] >>> 8;
            int count = compiledPattern[i  ] & 0xff;
            if (count == 255) {
                count = compiledPattern[i  ] << 16;
                count |= compiledPattern[i  ];
            }
            switch (tag) {
            case TAG_QUOTE_ASCII_CHAR:
                toAppendTo.append((char)count);
                break;
            case TAG_QUOTE_CHARS:
                toAppendTo.append(compiledPattern  i  count);
                i  = count;
                break;
            default:
                subFormat(tag  count  delegate  toAppendTo  useDateFormatSymbols);
                break;
            }
        }
        return toAppendTo;
    }
FastDateFormat如何处理的呢
    
那么FastDateFormat为什么是线程安全的呢?首先FastDateFormat是有一个缓存的,在进行实例化的时候是通过cache缓存来获取实例的
private static final FormatCache<FastDateFormat> cache= new FormatCache<FastDateFormat>() {
        @Override
        protected FastDateFormat createInstance(final String pattern  final TimeZone timeZone  final Locale locale) {
            return new FastDateFormat(pattern  timeZone  locale);
        }
    };
public static FastDateFormat getInstance(final String pattern) {
    return cache.getInstance(pattern  null  null);
}
    
将格式化格式、时区和国际化作为一个key存在了cInstanceCache中,cInstanceCache是一个ConcurrentHashMap,相当于相同的格式化格式、时区和国际化会使用同一个FastDateFormat实例
final MultipartKey key = new MultipartKey(pattern  timeZone  locale);
F format = cInstanceCache.get(key);
if (format == null) {           
    format = createInstance(pattern  timeZone  locale);
    final F previousValue= cInstanceCache.putIfAbsent(key  format);
    if (previousValue != null) {
        // another thread snuck in and did the same work
        // we should return the instance that is in ConcurrentMap
        format= previousValue;              
    }
}
    
而在进行格式化的时候Calendar使用的是方法内部的局部变量,是不会出现线程安全问题的
public String format(final Date date) {
    final Calendar c = newCalendar();
    c.setTime(date);
    return applyRulesToString(c);
}          




