我想在我的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/Montreal
、Africa/Casablanca
或Pacific/Auckland
。千万不要使用3-4个字母的缩写,如EST
或IST
,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
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东部标准时间
像ZonedDateTime
和Instant
这样的java.time对象也是不可变的并且是线程安全的,就像ZoneId
&DateTimeFormatter
。您可以缓存所有这些,并在线程之间使用它们。
关于java.time
java.time框架构建在Java8及更高版本中。这些类取代了诸如java.util.Date
、Calendar
、&CCD_ 22。
现在处于维护模式的JodaTime项目建议迁移到java.Time类。
要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR310。
您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。不需要字符串,也不需要java.sql.*
类。
从哪里获得java.time类?
- Java SE 8、Java SE 9及更高版本
- 内置
- 标准Java API的一部分,带有捆绑实现
- Java 9添加了一些小功能和修复程序
- Java SE 6和Java SE 7
- 大部分java.time功能都是向后移植到Java6&7英寸ThreeTen背包
- 安卓
- java.time类的Android捆绑包实现的后续版本
- 对于早期的Android(<26),ThreeTenABP项目适用于ThreeTen Backport(如上所述)。请参阅如何使用ThreeTenABP…
ThreeTen Extra项目通过附加类扩展java.time。这个项目是将来可能添加到java.time的试验场。您可以在这里找到一些有用的类,如Interval
、YearWeek
、YearQuarter
等等。
Apache Commons Lang有FastDateFormat
,它以正确的方式(在我看来)解决了这个问题,从一开始就是线程安全的:
FastDateFormat是SimpleDateFormat的一个快速且线程安全的版本。
在大多数格式化情况下,此类可以直接替换SimpleDateFormat。此类在多线程服务器环境中特别有用。SimpleDateFormat在任何JDK版本中都不是线程安全的,也不会像Sun关闭了bug/RFE那样。
对于这样的事情,您应该非常小心。标准(简单)格式化程序不是线程安全的。我在一些共享/缓存的格式化程序中遇到了一些与多线程相关的问题,但那是几年前的事了(Java 1.4)
同步
日期格式不同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问一个格式,则必须对其进行外部同步。