SimpleDateFormat以及线程安全

项目中,当多线程处理Date与String互相转换的时候,会出现ParseException转换异常。接着百度了一下,记录这个问题。

先贴一下原来的代码

处理的工具类 DateUtil

public class DateUtil {
	private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm::ss");

	static String formatDate(Date date) throws ParseException{
		return simpleDateFormat.format(date);
	}

	static Date parse(String dateStr){
		try {
			return simpleDateFormat.parse(dateStr);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}
}

创建20个线程,在子线程中调用parse方法。

public class Main {

    public static void main(String[] args) {

        for(int i = 0 ; i < 20 ; i ++){
            new Thread(() -> System.out.println(DateUtil.parse("2019-08-20 15:12:00"))).start();
        }
    }
}

这时候就能看到控制台输出出现了异常

输出的时间是错误的,并且抛出了多个异常。

那么,为什么呢?

来看看源码

SimpleDateFormat 继承自 DateFormat

在DateFormat中,有protected属性的Calendar,Calendar 处理的时候,牵扯到时区、本地化等问题,所以JDK中使用了成员变量来传递参数。bingo! 正是由于这个Calendar,导致了SimpleDateFormat线程不安全。

那么是不是可以在使用的时候再创建SimpleDateFormat对象?

可以是可以,将SimpleDateFormat局部私有可以解决上面的问题,但是创建多个对象会占用大量内存和JVM空间。程序员要优雅,应该还有更好的解决方案。

又是一通百度,终于找到了一篇博客。

点击这里打开博客

里面介绍了一种方法,使用 ThreadLocal 关于ThreadLocal点击这个连接

根据文章,重新编写一个测试类 NewDateUtil

public class NewDateUtil {

	private static ThreadLocal<DateFormat> threadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

	public static Date parse(String dateStr){
		try {
			return threadLocal.get().parse(dateStr);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}
	public static String format(Date date){
		return threadLocal.get().format(date);
	}
}

依然在main方法中调用


public class Main {

    public static void main(String[] args) {

        for(int i = 0 ; i < 20 ; i ++){
            new Thread(() -> System.out.println(NewDateUtil.parse("2019-08-20 15:12:00"))).start();
        }
    }
}

此时,可以输出正确的时间

另外,文章还提到了Joda-Time  。 Joda-Time的使用方法

Joda-Time 可以将ISO8601格式的String(e.g. R2/2015-06-04T19:25:16.828696-07:00/P1DT10S)转成Date ,但是对"yyyy-MM-dd HH:mm:ss"格式没有相应的方法(找到了再更新),

一般,SimpleDateFormat 局部私有可以解决线程安全的问题对性能影响不大,我自己倾向于使用ThreadLocal来解决

 

以上

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值