
SimpleDateFormat 的问题
在 Java 中,格式化日期通常使用 SimpleDateFormat 这个类。
我们知道,SimpleDateFormat 是线程不安全的,主要原因是 format 方法内部调用 calendar.setTime 方法,整个过程都是没有加锁或同步的,如果同时有多个线程调用到这一步,则会出现线程安全问题。
1 | public final String format(Date date) { |
所以,大部分时候则是在方法内部 new 出新的 DateFormat 对象再做格式化,如:DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
。
但在高访问量的情况下,频繁创建实例也会导致内存开销大和 GC 频繁问题。
FastDateFormat
Apache 的 commons-lang 包下有个 FastDateFormat 可以方便的解决上述问题。
查看其源码:
1 | // 2.6 版本源码 |
FastDateFormat 通过 getInstance 静态方法获取对象,内部加了一个 cInstanceCache 缓存。当使用同样的 pattern 格式化时会命中缓存,返回缓存中的对象,避免重复创建实例。
拿到对象调用 format 方法,可以看出 Calender 是在 format 方法中创建的,所以不会出现 setTime 的线程安全问题。
1 | public String format(Date date) { |
而且 getInstance 这个方法是加锁的,以保证获取实例的线程安全性。在新的版本(3.0 以上)中 getInstance 方法内更加使用 ConcurrentMap 做缓存提高并发性能。
1 | // 3.0 版本源码 |
DateFormatUtils
基于上面 FastDateFormat 类,commons-lang 包还提供了 DateFormatUtils 工具类,提供了两方面的功能:
- 提供静态的 format 方法,实现一行代码格式化日期。
- 内部初始化了一些 final 的 FastDateFormat,方便开发者直接调用。