与普通日期格式化对比,FastDateFormat 为何能线程安全?

FastDateFormat为什么线程安全

SimpleDateFormat的线程不安全

大家都知道SimpleDateFormat是线程不安全的

java 复制代码
protected Calendar calendar;

SimpleDateFormat中的calendar是成员变量,同实例多个线程下会共享该calendar对象

而在进行格式化的时候可能会由于第一个线程还没有格式化完成,而第二个线程已经将时间修改了的情况

java 复制代码
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缓存来获取实例的

java 复制代码
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实例

java 复制代码
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;              
    }
}

而在使用FastDateFormat进行格式化的时候,是在方法中定义的Calendar局部变量,是不会出现线程安全问题的

java 复制代码
public String format(final Date date) {
    final Calendar c = newCalendar();
    c.setTime(date);
    return applyRulesToString(c);
}

参考文献

相关推荐
黑客-雨1 天前
DeepSeek-V3.2深度拆解:开源模型逆袭,GPT-5迎来劲敌!
人工智能·程序员·大模型·知识图谱·agent·大模型教程·deepseek-v3.2
紫雾凌寒1 天前
【 HarmonyOS 高频题】2026 最新 ArkUI 开发与组件面试题
ui·华为·面试·程序员·职场发展·harmonyos·ark-ui
IT技术分享社区3 天前
GTID 结构升级 + JSON 视图强化,MySQL 9.6 创新版带来哪些性能提升?
数据库·程序员
小阿鑫3 天前
32岁程序员猝死背后,我的一些真实感受
前端·后端·程序员·代码人生
十年编程老舅4 天前
虾皮C++一面:C++四种类型转换详解
程序员·编程·c/c++
紫雾凌寒4 天前
【 HarmonyOS 面试题】2026 最新 ArkTS 语言基础面试题
华为·面试·程序员·华为云·职场发展·harmonyos·arkts
程序员鱼皮6 天前
20 个神级 AI 编程扩展,爽爆了!
ai·程序员·编程
一晌小贪欢9 天前
Python 异步编程深度解析:从生成器到 Asyncio 的演进之路
开发语言·python·程序员·python基础·python小白·python测试
京东云开发者10 天前
如何使用wireshark进行远程抓包
程序员
京东云开发者10 天前
InheritableThreadLocal从入门到放弃
程序员