SimpleDateFormat引发的multiple points 异常以及问题解决

问题背景

前段时间开发的时候,一个页面加载数据的时候,两处地方调用两个接口,测试的时候发现有的时候会报错抛出异常,有的时候正正常请求,但是开发的时候没有问题,这就很奇怪,看了报错信息之后,才发现是 java.lang.NumberFormatException异常,信息为multiple points,百度之后才发现问题所在,特此记录一下。

问题分析

两处地方都有用到自己封装的日期工具类来处理日期格式,这个时候多线程下就会存在SimpleDateFormat并发问题了

然后我自己测试,发现会有以下几种报错

1. java.lang.NumberFormatException: multiple points

2. java.lang.NumberFormatException: empty String

3. java.lang.NumberFormatException: For input string: ""

追究根源,其实

SimpleDateFormat的format方法和parse方法都因为使用calendar来操作时间

而calendar是共享变量,并且这个共享变量没有做线程安全控制

我们可以看看源码分析

format方法

当多个线程同时使用相同的SimpleDateFormat对象【用static修饰的SimpleDateFormat】调用format方法时,多个线程会同时调用calendar.setTime方法,

可能一个线程刚设置好time值,另外的一个线程马上把设置的time值给修改了导致返回的格式化时间可能是错误的。

parse方法

parse方法实际调用alb.establish(calendar).getTime()方法来解析,

alb.establish(calendar)方法里主要任务是

  • 重置日期对象cal的属性值
  • 使用calb中中属性设置cal
  • 返回设置好的cal对象

在parse方法的最后,会调用CalendarBuilder的establish方法,入参就是SimpleDateFormat维护的Calendar实例,

在establish方法中会调用calendar的clear方法

SimpleDateFormat维护的用于format和parse方法处理时间的calendar被清空了

如果此时线程A将calendar清空且没有设置新值,线程B也进入parse方法用到了SimpleDateFormat对象中的calendar对象,此时就会产生线程安全问题!

解决方案

  1. 避免线程之间共享一个SimpleDateFormat对象,每个线程使用时都创建一次SimpleDateFormat对象 => 创建和销毁对象的开销大
  2. 对使用format和parse方法的地方进行加锁 => 线程阻塞性能差
  3. 使用ThreadLocal保证每个线程最多只创建一次SimpleDateFormat对象 => 较好的方法
  4. 换个日期处理API。 Java8新增的 LocalDate、LocalTime、LocalDateTime

DateTimeFormatter默认提供了多种格式化方式,如果默认提供的不能满足要求,

可以通过DateTimeFormatter的ofPattern方法创建自定义格式化方式

LocalDate localDate1 = LocalDate.parse("20190910", DateTimeFormatter.BASIC_ISO_DATE); 
LocalDate localDate2 = LocalDate.parse("2019-09-10", DateTimeFormatter.ISO_LOCAL_DATE);
// 和SimpleDateFormat相比,DateTimeFormatter是线程安全的
// 2020-05-09 17:38:57
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值