线程非安全的 SimpleDateFormat

JDK 中的 SimpleDateFormat 是线程非安全的, 因此当在并发访问的情形下使用时一定要当心。尽管 Javadoc API 文档中明确指出了该类是未同步的,可能很多人在遇到了其导致的问题之前都不会注意到这点。

先看个例子。

上述示例程序启动了五个线程,各线程都使用共享的 SimpleDateFormat 用来解析时间戳字符串。多运行几次上面的程序,很可能地你可能会看到下述结果或异常信息中的一种:

  1. Exception in thread "Thread-4" java.lang.NumberFormatException: For input string: ""
  2. Exception in thread "Thread-1" java.lang.NumberFormatException: multiple points
  3. Thu Jun 27 10:33:09 CST 2024
  4. Exception in thread "Thread-2" java.lang.NumberFormatException: empty String
  5. Fri Jun 27 10:33:09 CST 2200
  6. ......

如上所示,有时得到的是异常(大部分情况是 NumberFormatException: For input string: ""),有时给出的是错误的结果。

为了避免以上问题,可以在每次使用其解析或格式化字符串时都创建一个新的  SimpleDateFormat 实例。显然,这种处理方式在并发量大时并不是一个很节约的方式。一种更优化的方式是使用 ThreadLocal 变量存放,使得每个线程都独立的有一份 SimpleDateFormat , 通常来说你还可以将创建的实例进行缓存。该方案的实现细节请参考这篇 Jesper’s blog post, 文中还有对各解决方案性能的对比。