Java 我有一个日期对象,需要格式化它以进行缓存查找,SimpleDataFormat是';t线程安全?

Java 我有一个日期对象,需要格式化它以进行缓存查找,SimpleDataFormat是';t线程安全?,java,spring,datetime,spring-mvc,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,H

在我的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静态方法从日期获取密钥。

使用

公共类DateHelpers{
私有静态final ThreadLocal minuteDateFormat=new ThreadLocal(){
@重写受保护的DateFormat初始值(){
返回新的SimpleDataFormat(“yyyy-MM-dd,HH:MM”,Locale.US);
}
};
公共静态字符串getDateKey(当前日期){
DateFormat df=minuteDateFormat.get();
//使用df格式化日期
}
}
使用一个

公共类DateHelpers{
私有静态final ThreadLocal minuteDateFormat=new ThreadLocal(){
@重写受保护的DateFormat初始值(){
返回新的SimpleDataFormat(“yyyy-MM-dd,HH:MM”,Locale.US);
}
};
公共静态字符串getDateKey(当前日期){
DateFormat df=minuteDateFormat.get();
//使用df格式化日期
}
}
试试这个

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;
  }
}
公共类DateFormatTest{
私有静态最终线程本地df
=新线程本地(){
@凌驾
受保护的日期格式初始值(){
返回新的SimpleDataFormat(“yyyy-MM-dd,HH:MM”,Locale.US);
}
};
公共日期转换(字符串源)
抛出解析异常{
日期d=df.get().parse(源代码);
返回d;
}
}
试试这个

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;
  }
}
公共类DateFormatTest{
私有静态最终线程本地df
=新线程本地(){
@凌驾
受保护的日期格式初始值(){
返回新的SimpleDataFormat(“yyyy-MM-dd,HH:MM”,Locale.US);
}
};
公共日期转换(字符串源)
抛出解析异常{
日期d=df.get().parse(源代码);
返回d;
}
}
您也可以尝试使用Joda time API。它是不可变的且线程安全的。

您也可以从Joda time API尝试。它是不可变且线程安全的。

from是线程安全的。此外,通过将ThreadLocal子类化,您不会创建类加载器泄漏。但是,它只进行格式化,不进行解析

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

from是线程安全的。此外,通过将ThreadLocal子类化,您不会创建类加载器泄漏。但是,它只进行格式化,不进行解析


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

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

如果你想把它四舍五入到一分钟,你可以用整数除以60000,这会更快,并且保证线程安全

对于设置日期格式的情况,我通常会根据需要创建日期格式(这并不昂贵),或者我有一个与每个辅助对象显式关联的实用程序对象池


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

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

如果你想把它四舍五入到一分钟,你可以用整数除以60000,这会更快,并且保证线程安全

对于设置日期格式的情况,我通常会根据需要创建日期格式(这并不昂贵),或者我有一个与每个辅助对象显式关联的实用程序对象池


线程本地解决方案可以工作,但随着时间的推移,很容易失去对所有TL的跟踪,最终导致代码更难调试。

来自javadoc for SimpleDataFormat:

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


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

来自javadoc for SimpleDataFormat:

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

太多的开发人员看到了这一点,他们的第一反应就是在ThreadLocal上进行同步或添加同步块。在您了解它之前,代码中充斥着ThreadLocal,通常是作为“预防措施”,但并非出于必要。它可以变成增量
protected static DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd,HH:mm");