与普通日期格式化对比,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);
}

参考文献

相关推荐
人邮异步社区2 小时前
想要系统地学习扩散模型,应该怎么去做?
人工智能·学习·程序员·扩散模型
SelectDB7 小时前
Apache Doris 在小米统一 OLAP 和湖仓一体的实践
运维·数据库·程序员
文心快码BaiduComate7 小时前
Agent如何重塑跨角色协作的AI提效新范式
前端·后端·程序员
大模型教程9 小时前
爆肝6周,手把手教你搭建一套生产级RAG论文研究助手
程序员·llm·agent
大模型教程9 小时前
技术干货丨AI 大模型微调到底是什么?一篇通俗文帮你弄明白
程序员·llm·agent
陈随易9 小时前
MoonBit语法基础概述
前端·后端·程序员
AI大模型11 小时前
别再瞎学大模型了,这份GitHub神级课程火爆全网
程序员·llm·agent
程序员鱼皮11 小时前
MySQL 从入门到删库跑路,保姆级教程!
java·计算机·程序员·编程·编程经验
AI大模型11 小时前
检索增强生成(RAG)与大语言模型微调(Fine-tuning)的差异、优势及使用场景详解
程序员·llm·agent