行业资讯 2025年08月6日
0 收藏 0 点赞 451 浏览 2451 个字
摘要 :

文章目录 一、SimpleDateFormat为何线程不安全 二、FastDateFormat实现线程安全的原理 (一)实例缓存机制 (二)局部变量的使用 Java开发中,日期格式化是一个常见的……




  • 一、SimpleDateFormat为何线程安全
  • 二、FastDateFormat实现线程安全的原理
    • (一)实例缓存机制
    • (二)局部变量的使用

    Java开发中,日期格式化是一个常见的操作。我们都知道SimpleDateFormat,但它存在线程不安全的问题。与之相比,FastDateFormat却能实现线程安全,这背后的原因是什么呢?

    一、SimpleDateFormat为何线程不安全

    SimpleDateFormat在多线程环境下是不安全的,这是很多开发者都清楚的事情。我们来看看它的内部代码,其中有一个protected Calendar calendar;成员变量。这意味着,当多个线程使用同一个SimpleDateFormat实例时,它们会共享这个calendar对象。
    在进行日期格式化的过程中,就容易出现问题。下面是SimpleDateFormat的格式化方法部分代码:

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

    当第一个线程调用calendar.setTime(date)设置时间后,还没来得及将其格式化为字符串,第二个线程可能就把时间给修改了,这样就会导致数据混乱,出现线程安全问题。

    二、FastDateFormat实现线程安全的原理

    (一)实例缓存机制

    FastDateFormat之所以能做到线程安全,首先得益于它的缓存机制。在实例化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 cache.getInstance(pattern, null, null);
    }
    

    它把格式化格式、时区和国际化这些信息组合成一个键,存放在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;              
        }
    }
    

    这种方式减少了重复创建实例的开销,同时也为线程安全提供了一定保障。

    (二)局部变量的使用

    除了缓存机制,FastDateFormat在格式化方法中也做了巧妙处理。来看它的格式化方法代码:

    public String format(final Date date) {
        final Calendar c = newCalendar();
        c.setTime(date);
        return applyRulesToString(c);
    }
    

    在这个方法里,Calendar是局部变量。每个线程在调用format方法时,都会创建自己的Calendar对象,这样就避免了多个线程共享同一个Calendar对象带来的线程安全问题。

    通过上述对SimpleDateFormat线程不安全原因的剖析,以及对FastDateFormat实现线程安全原理的讲解,我们可以清晰地看到两者的差异。在多线程环境下进行日期格式化操作时,FastDateFormat是一个更可靠的选择。

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/10371.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

988
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

465
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

348
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

456
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

517
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

832
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号