同步对 SimpleDateFormat 的访问

SimpleDateFormat 的 javadoc 声明 SimpleDateFormat 未同步。

“日期格式不同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问一种格式,则必须在外部同步该格式。

但是,在多线程环境中使用 SimpleDateFormat 实例的最佳方法是什么?以下是我想到的一些选项,我过去使用过选项1和2,但我很好奇是否有更好的替代方案,或者这些选项中的哪一个可以提供最佳的性能和并发性。

选项 1:在需要时创建本地实例

public String formatDate(Date d) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    return sdf.format(d);
}

选项 2:将 SimpleDateFormat 的实例创建为类变量,但同步对它的访问。

private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public String formatDate(Date d) {
    synchronized(sdf) {
        return sdf.format(d);
    }
}

选项 3:创建一个 ThreadLocal 以为每个线程存储一个不同的 SimpleDateFormat 实例。

private ThreadLocal<SimpleDateFormat> tl = new ThreadLocal<SimpleDateFormat>();
public String formatDate(Date d) {
    SimpleDateFormat sdf = tl.get();
    if(sdf == null) {
        sdf = new SimpleDateFormat("yyyy-MM-hh");
        tl.set(sdf);
    }
    return sdf.format(d);
}

答案 1
  1. 创建SimpleDateFormat是昂贵的。除非很少这样做,否则不要使用它。

  2. 好吧,如果你能忍受一点阻塞。如果 formatDate() 使用不多。

  3. 最快的选项,如果您重用线程(线程池)。使用超过 2 的内存。并具有更高的启动开销。

对于应用程序两者 2.和 3.是可行的选择。哪种情况最适合您的情况取决于您的使用案例。当心过早优化。只有当您认为这是一个问题时,才这样做。

对于将由第三方使用的库,我将使用选项3。


答案 2

另一个选项是Commons Lang FastDateFormat,但你只能用它来格式化日期,不能用于解析。

与Joda不同,它可以作为格式化的直接替代品。(更新:从v3.3.2开始,FastDateFormat可以生成FastDateParser,这是SimpleDateFormat的直接线程安全替代品)


推荐