我有一个日期对象,需要格式化它以进行缓存查找,simpledateformat不是线程安全的吗?

时间:2012-04-24 14:39:12

标签: java spring datetime spring-mvc

在我的servlet中,当一个请求进来时,我创建了一个日期对象。

Date now = new Date();

我想执行缓存查找,我需要创建一个帮助函数,将日期格式化为:

2012.04.24-10:34

是:yyyy-MM-dd,HH:mm

我使用简单的日期格式:

public class DateHelpers {
      public static final DateFormat minuteDateFormat = new SimpleDateFormat("yyyy-MM-dd,HH:mm", Locale.US);

      public static String getDateKey(Date now) {
         // use minuteDateFormat to format date
      }
}

但我读到的简单日期格式不是线程安全的。

我没有将字符串解析为dateformat,所以也许有更好更快的方法来做到这一点?

我正在使用日期对象并将其格式化为字符串,并且它必须是线程安全的,因为许多请求将使用此DateHelper静态方法从日期获取密钥。

7 个答案:

答案 0 :(得分:5)

退后一步,如果你真的要求性能,我会避免格式化日期,只需使用unix时间戳作为键(即System.currentTimeMllis())。如果要基于现有日期对象date.getTime()进行查找,则会为您提供时间戳。

如果你想把它舍入到一分钟,你可以将它除以并乘以60,000 - 它的速度更快,并保证线程安全。

对于格式化日期的情况,我通常要么按需创建日期格式( 昂贵),或者我有一个实用程序对象池,我明确地与每个工作者关联。

线程本地解决方案将起作用,但随着时间的推移,很容易失去对所有TL的跟踪,并且最终会得到更难以调试的代码。

答案 1 :(得分:4)

使用ThreadLocal<DateFormat>

public class DateHelpers {
    private static final ThreadLocal<DateFormat> minuteDateFormat = new ThreadLocal<DateFormat>() {
        @Override protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd,HH:mm", Locale.US);
        }
    };

    public static String getDateKey(Date now) {
        DateFormat df = minuteDateFormat.get();
       // use df to format date
    }
}

答案 2 :(得分:3)

java.time

java.time框架内置于Java 8及更高版本中。 (见Tutorial。)

包含一个新的日期格式化程序,是线程安全的DateTimeFormatter

另一个优点是在格式化模式中支持可选部分。

它的创建将是这样的:

protected static DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd,HH:mm");

答案 3 :(得分:1)

来自SimpleDateFormat的javadoc:

  

建议为每个线程创建单独的格式实例。

太多开发人员看到了这一点,他们的第一直觉是在ThreadLocal上同步或添加同步块。在您知道它之前,代码中充满了ThreadLocal,通常作为“预防措施”,但不是必需的。排除故障可能会非常困难。除非绝对没有替代方案,否则没有理由使用本地线程同步您的格式。如果你真的有一个永远不会改变的日期格式(为什么用给定的字符串格式将它标记为静态final),那么你真正需要的是在JVM中创建的那个日期格式的实例。在应用程序启动时,最好使用控制反转来注入简单的日期格式。这样,当你在任何地方需要它时,你知道它存在。

答案 4 :(得分:0)

试试这个

public class DateFormatTest {

  private static final ThreadLocal<DateFormat> df
                 = new ThreadLocal<DateFormat>(){
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd,HH:mm", Locale.US);
    }
  };

  public Date convert(String source)
                     throws ParseException{
    Date d = df.get().parse(source);
    return d;
  }
}

答案 5 :(得分:0)

您也可以尝试使用Joda time API中的DateTimeFormat。它是不可变的和线程安全的。

答案 6 :(得分:0)

来自FastDateFormat

commons-lang是线程安全的。此外,您不会通过继承ThreadLocal来创建ClassLoader-leaks。但是它只进行格式化,而不进行解析。

另一种选择是具有无状态且因此线程安全的解析器和格式化程序的优秀joda-time库。