解读阿里巴巴Java手册:为什么禁止把SimpleDateFormat设为static

SimpleDateFormat介绍

SimpleDateFormat用于以区域设置敏感的方式格式化和解析日期。 它允许格式化(日期文本),解析(文本日期)和归一化。
日期和时间格式由日期和时间模式字符串指定。 在日期和时间模式字符串中,从’A’到’Z’和从’a’到’z’的非引号的字母被解释为表示日期或时间字符串的组件的模式字母。 可以使用单引号( ’ )引用文本,以避免解释。 "’’"代表单引号。 所有其他字符不被解释; 在格式化过程中,它们只是复制到输出字符串中,或者在解析过程中与输入字符串匹配。
在这里插入图片描述

例子

以下示例显示如何在美国地区中解释日期和时间模式。 给定的日期和时间是2001-07-04 12:08:56当地时间在美国太平洋时间时区。
在这里插入图片描述

什么情况下static定义的会出现错误

public class Demo {
	//定义一个静态SimpleDateFormat
	private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	//线程数量
	static int num = 100;
	//定义同步辅助工具,主线程等待所有子线程执行完毕
	private static CountDownLatch countDownLatch = new CountDownLatch(num);
	
	public static void main(String[] args) throws InterruptedException {
		//一个线程安全的set,去重
		Set<String> dateSet = Collections.synchronizedSet(new HashSet<>());
		for (int i = 0; i < num; i++) {
			 int j = i;
			new Thread() {
				@Override
				public void run() {
					//获取使用默认时区和地区的日历。返回的日历基于默认时区中的当前时间
					Calendar calendar = Calendar.getInstance();
					//每次循环在当天是的时间上+i天,理想状态下最后时间是当前时间的100天后
					calendar.add(Calendar.DATE, j);
					//格式化
					String dateString = simpleDateFormat.format(calendar.getTime());
	                //把字符串放入Set中
					dateSet.add(dateString);
	                //countDown
	                countDownLatch.countDown();
				}
			}.start();
		}
		//阻塞,直到countDown数量为0
        countDownLatch.await();
        //输出去重后的时间个数
        System.out.println(dateSet.size());
	}
	
}

这段代码理想状态下最后输出的为100,但是结果并不是,为什么会这样呢?
在JDK官方文档中这样描述:
在这里插入图片描述
SimpleDateFormat 并不是一个线程安全的类。

看下SimpleDateFormat的format是如何实现的

在这里插入图片描述
SimpleDateFormat中的format方法在执行过程中,会使用一个成员变量calendar来保存时间。这其实就是问题的关键。

由于我们在声明SimpleDateFormat的时候,使用的是static定义的。那么这个SimpleDateFormat就是一个共享变量,随之,SimpleDateFormat中的calendar也就可以被多个线程访问到。

假设线程1刚刚执行完calendar.setTime把时间设置成2018-11-11,还没等执行完,线程2又执行了calendar.setTime把时间改成了2018-12-12。这时候线程1继续往下执行,拿到的calendar.getTime得到的时间就是线程2改过之后的。

除了format方法以外,SimpleDateFormat的parse方法也有同样的问题。

所以,不要把SimpleDateFormat作为一个共享变量使用。

如何解决

1. 使用SimpleDateFormat局部变量

2. 加同步锁synchronized

3. 使用DateTimeFormatter

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦里藍天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值