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

问题背景

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

问题分析

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

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

1. java.lang.NumberFormatException: multiple points

SimpleDateFormat引发的multiple points 异常以及问题解决_第1张图片

2. java.lang.NumberFormatException: empty String

SimpleDateFormat引发的multiple points 异常以及问题解决_第2张图片

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

SimpleDateFormat引发的multiple points 异常以及问题解决_第3张图片

追究根源,其实

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

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

我们可以看看源码分析

format方法

SimpleDateFormat引发的multiple points 异常以及问题解决_第4张图片

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

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

parse方法

SimpleDateFormat引发的multiple points 异常以及问题解决_第5张图片

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"));

 

 

 

 

 

 

你可能感兴趣的:(JAVA)