使用 SimpleDateFormat 时奇怪的 NumberFormatException
文章目录
2019-09-01 更新:
从 JDK 8 开始,本文描述的问题已经不是问题了。因为 JDK 8 带来了全新的 Date Time API。大体上来说,这套 API 吸收了 Joda Time 的优点,相当清晰、简单且灵活。同时,所有的时间表示都是不可变类,因此也天然是线程安全的。当然,SimpleDateFormat
的问题也有了更优雅的工具替代。
对时间的格式化和解析的用法对比如下:
|
|
|
|
原文:
JDK 中的 SimpleDateFormat
是线程非安全的, 因此当在并发访问的情形下使用时一定要当心。尽管 Javadoc API 文档中明确指出了该类是未同步的,可能很多人在遇到了其导致的问题之前都不会注意到这点。
先看个例子。
|
|
上述示例程序启动了五个线程,各线程都使用共享的 SimpleDateFormat
用来解析时间戳字符串。多运行几次上面的程序,很可能地你可能会看到下述结果或异常信息中的一种:
- Exception in thread “Thread-4” java.lang.NumberFormatException: For input string: “”
- Exception in thread “Thread-1” java.lang.NumberFormatException: multiple points
- Thu Jun 27 10:33:09 CST 2024
- Exception in thread “Thread-2” java.lang.NumberFormatException: empty String
- Fri Jun 27 10:33:09 CST 2200
- ……
如上所示,有时得到的是异常(大部分情况是 NumberFormatException: For input string: ""
),有时给出的是错误的结果。
为了避免以上问题,可以在每次使用其解析或格式化字符串时都创建一个新的 SimpleDateFormat
实例。显然,这种处理方式在并发量大时并不是一个很节约的方式。一种更优化的方式是使用 ThreadLocal
变量存放,使得每个线程都独立的有一份 SimpleDateFormat
, 通常来说你还可以将创建的实例进行缓存。该方案的实现细节请参考这篇 Jesper’s blog post, 文中还有对各解决方案性能的对比。
文章作者 董干
上次更新 2019-09-01