这几天在开发一个接口的时候,内部调用了一个别人查询数据的接口,发到正式环境测试的时候一直报错,如下图所示:
从图中可以看出是代码中122行除了问题,代码中122行是这样的:
所以很自然的想到了是日期格式转换错误,加上日志把temp输出了一下:
格式基本都正确,并没有我想象当中的空字符串。
这时候突然注意到一个问题
我的报错是NumberFormatException而不是ParseFormatException,如果按我的猜测,输入空字符串导致格式转换,那么应该是ParseFormatException,如下图所示:
所以问题应该不是格式的问题,百度了一下,才知道原来是多线程的问题,SimpleDateFormat是不安全的,如果在同一时间有多个线程使用他,那么极有可能造成该问题,这种场景很符合我的业务,于是我在代码中为其单独定义一个SimpleDateFormat后在测试,果然解决了该问题。
那么问题来了,SimpleDateFormat为什么不安全呢?
我们看下源码,可以看到SimpleDateFormat的parse方法调自父类DateFormat的parse方法,而DateFormat的parse方法调用了parse抽象方法,该抽象方法被SimpleDateFormat实现
接下来我和我查询的资料有些分歧,我查阅到的资料认为这个多线程问题是因为源码中这一段代码:
establish(calendar)
方法中会有一个calendar.clear操作,如果两个线程A、B同时进入该方法,A方法在执行完之后,将calendar清除了,那么B线程此时拿到的calendar就是为空,就出现了多线程问题;
但是我觉得并不是这里的问题,首先根据图1的报错信息,我们可以注意到栈跟踪并没有跟踪到这一块儿,而是跟踪到了SimpleDateFormat.parse方法中的第1869行的subParse方法;其次,Calendar.clear方法根据官方文档,只是将Calendar设置为1970年,并不会导致报错。
但是,我把这边的源码看了一遍,并没有发现这个地方会出现问题。。。就很没有说服力。
这篇文章主要就是为了说明DateFormat的线程不安全问题,但是为何是不安全,目前来说,这两个观点都无法说服我自己,希望有大佬看了之后能指正一下。