1

在我的 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
      }
}

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

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

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

4

7 回答 7

5

退后一步,如果您真的很想提高性能,我会完全避免格式化日期,而只使用 unix 时间戳作为键(即 System.currentTimeMllis())。如果您想根据现有日期对象进行查找,date.getTime()则会为您提供时间戳。

如果你想将它舍入到一分钟,你可以整数除法和乘以 60,000 - 它更快并且保证线程安全。

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

线程本地解决方案将起作用,但随着时间的推移,很容易忘记所有 TL,最终得到更难调试的代码。

于 2012-04-24T14:58:53.023 回答
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
    }
}
于 2012-04-24T14:41:40.080 回答
3

java.time

The java.time framework is built into Java 8 and later. (See Tutorial.)

Included is a new date formatter which is thread-safe: DateTimeFormatter.

Another advantage is the support of optional parts in the formatting pattern.

Its creation will be like this:

protected static DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd,HH:mm");
于 2016-03-19T12:46:24.513 回答
1

来自 SimpleDateFormat 的 javadoc:

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

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

于 2012-04-24T15:17:50.220 回答
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;
  }
}
于 2012-04-24T14:44:10.550 回答
0

您也可以从 Joda 时间 API尝试DateTimeFormat 。它是不可变的和线程安全的。

于 2012-04-24T14:50:04.673 回答
0

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

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

于 2012-04-24T14:51:21.177 回答