SimpleDateFormat为什么是线程不安全的?

SimpleDateFormat为什么是线程不安全的?

前言

其实这已经是个老生常谈的问题了,这篇博客旨在提醒自己,方便回忆。同时希望可以帮助到需要的伙伴。如果有哪些地方有错误或不合适,欢迎大家指出。

我不知道它是线程不安全的之前,在做日期格式转换的时候,我对它情有独钟。直到有一天代码Review的时候,老大告诉这玩意是线程不安全!
在这里插入图片描述
为啥?看看去!

原因

简明意赅的说就是:
SimpleDateFormate的parse()方法会用到它爹申明的一个属性calendar。多线程操作同一个calendar对象的时候就可能会产生线程安全问题

可能会产生问题的代码

        try {
        	// 源码大概在SimpleDateFormat类的1532行处
        	// 这里是将calb中的处理好的时间信息传递到calendar中
            parsedDate = calb.establish(calendar).getTime();
           	...
           	...
        }

让我们走进establish( )的内心世界看一下

		//源码在CalendarBuilder类的103处
		...
		//这里先进行了一个clear()操作
		cal.clear();

		//如下进行了一个赋值操作
        for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
            for (int index = 0; index <= maxFieldIndex; index++) {
                if (field[index] == stamp) {
                    cal.set(index, field[MAX_FIELD + index]);
                    break;
                }
            }
        }

        if (weekDate) {
            int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
            int dayOfWeek = isSet(DAY_OF_WEEK) ?
                                field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
            if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
                if (dayOfWeek >= 8) {
                    dayOfWeek--;
                    weekOfYear += dayOfWeek / 7;
                    dayOfWeek = (dayOfWeek % 7) + 1;
                } else {
                    while (dayOfWeek <= 0) {
                        dayOfWeek += 7;
                        weekOfYear--;
                    }
                }
                dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
            }
            cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
        }
        //这里是将处理完了calendar返回
        return cal;

这个calendar对象在当前方法中被清理并被重新赋值,在多线程的环境下,如果A线程clear()完毕后正在对calendar对象进行重新赋值。
就是此时,啪!B线程跑进来了,给calendar又clear()了!这不就GG了嘛!
在这里插入图片描述在这里插入图片描述
上面提到的这个calendar来自SimpleDateFormat的父类DateFormat

public abstract class DateFormat extends Format {

    /**
     * The {@link Calendar} instance used for calculating the date-time fields
     * and the instant of time. This field is used for both formatting and
     * parsing.
     *
     * <p>Subclasses should initialize this field to a {@link Calendar}
     * appropriate for the {@link Locale} associated with this
     * <code>DateFormat</code>.
     * @serial
     */
    protected Calendar calendar;
    ...
}

public class SimpleDateFormat extends DateFormat {
	...
}    

当前对于SimpleDateFormat的线程不安全问题其实有众多的解决方法,比如

  1. 一个线程给NEW 一个对象(强烈不推荐的咯)
  2. 加锁!(例如synchronized,咱就是说,影响程序执行效率,其实也不是很推荐)
  3. ThreadLocal来处理(等KK弄明白了这玩意再来扯犊子🤩)
  4. 和我一样使用DateTimeFormatter类👀

结束

散会!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值