是否有一个好的线程安全格式缓存库



我想在我的Web应用程序中使用MessageFormat、DateFormat、DecimalFormat等进行一些格式化。

由于这些不是线程安全的,每次使用一个静态实例是不起作用的,但每次需要创建一个新的XXXXFormat对象似乎是浪费。缓存并使用ThreadLocal重新使用它们似乎是一个明显的优化。

这似乎是一种非常常见的模式,所以我想知道是否有合适的库。

而不是调用:

    DecimalFormat formatter = new DecimalFormat("###,##0.00");
    String formatted = formatter.format(value);             

每次我需要格式化一些东西,为什么不呢:

    String formatted = FormatCache.formatDecimal("###,##0.00",numberValue);

FormatCache将在哪里使用基于格式模式的HashMap进行ThreadLocal缓存?

大概还有其他方法,比如:

    String FormatCache.formatDecimal(String, Number);
    String FormatCache.formatDate(String, Date);
    String FormatCache.formatMessage(String, Object...);

tl;dr

缓存线程安全的DateTimeFormatter对象(不可变)。

切勿使用SimpleDateFormat对于日期时间工作,仅使用java.time包。

java.time

诸如DateFormat&SimpleDateFormat现在被现代的java.time类所取代。具体来说,这里是DateTimeFormatter类。

不可变对象,线程安全

java.time类被设计为不可变对象。这意味着生成一个新的不同对象,而不是修改对象中的任何内容。原件完好无损。

这一点和其他技术使java.time类在设计上是线程安全的,并且有文档记录。

DateTimeFormatter

DateTimeFormatter dateTimeFormatterFullQuébec = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ;

您可以缓存该对象dateTimeFormatterFullQuébec,并将其保留在周围。

ZoneId

同样,您可以缓存ZoneId时区对象。

continent/region的格式指定适当的时区名称,例如America/MontrealAfrica/CasablancaPacific/Auckland。千万不要使用3-4个字母的缩写,如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId zoneMontréal = ZoneId.of( "America/Montreal" ) ;

然后随时使用它们,甚至可以跨线程使用。

ZonedDateTime zdt = ZonedDateTime.now( zoneMontréal ) ;
String output = zdt.format( dateTimeFormatterFullQuébec ) ;

迪曼奇4 mars 2018à18:36:32东部标准时间

ZonedDateTimeInstant这样的java.time对象也是不可变的并且是线程安全的,就像ZoneId&DateTimeFormatter。您可以缓存所有这些,并在线程之间使用它们。


关于java.time

java.time框架构建在Java8及更高版本中。这些类取代了诸如java.util.DateCalendar、&CCD_ 22。

现在处于维护模式的JodaTime项目建议迁移到java.Time类。

要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR310。

您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。不需要字符串,也不需要java.sql.*类。

从哪里获得java.time类?

  • Java SE 8Java SE 9及更高版本
    • 内置
    • 标准Java API的一部分,带有捆绑实现
    • Java 9添加了一些小功能和修复程序
  • Java SE 6Java SE 7
    • 大部分java.time功能都是向后移植到Java6&7英寸ThreeTen背包
  • 安卓
    • java.time类的Android捆绑包实现的后续版本
    • 对于早期的Android(<26),ThreeTenABP项目适用于ThreeTen Backport(如上所述)。请参阅如何使用ThreeTenABP…

ThreeTen Extra项目通过附加类扩展java.time。这个项目是将来可能添加到java.time的试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等等。

Apache Commons Lang有FastDateFormat,它以正确的方式(在我看来)解决了这个问题,从一开始就是线程安全的:

FastDateFormat是SimpleDateFormat的一个快速且线程安全的版本。

在大多数格式化情况下,此类可以直接替换SimpleDateFormat。此类在多线程服务器环境中特别有用。SimpleDateFormat在任何JDK版本中都不是线程安全的,也不会像Sun关闭了bug/RFE那样。

对于这样的事情,您应该非常小心。标准(简单)格式化程序不是线程安全的。我在一些共享/缓存的格式化程序中遇到了一些与多线程相关的问题,但那是几年前的事了(Java 1.4)

同步

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

最新更新