我想在我的webapp中使用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...);
答案 0 :(得分:5)
Apache Commons Lang有FastDateFormat
,它以正确的方式解决问题(在我看来),只是以线程安全开头:
FastDateFormat是SimpleDateFormat的快速且线程安全的版本。
在大多数格式化情况下,此类可用作SimpleDateFormat的直接替换。此类在多线程服务器环境中特别有用。 SimpleDateFormat在任何JDK版本中都不是线程安全的,也不会像Sun关闭bug / RFE那样。
答案 1 :(得分:4)
缓存线程安全DateTimeFormatter
对象(不可变)。
从不使用SimpleDateFormat
。仅使用 java.time 包进行日期工作。
麻烦的旧日期时间类,例如DateFormat
& SimpleDateFormat
现在已被现代 java.time 类取代。具体来说,就是DateTimeFormatter
类。
java.time 类设计为Immutable Objects。这意味着不是修改对象中的任何内容,而是生成新的不同对象。原件保持不变。
这个和其他技术通过设计制作了 java.time 类thread-safe,并且是如此记录的。
DateTimeFormatter
DateTimeFormatter dateTimeFormatterFullQuébec = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ;
您可以缓存该对象dateTimeFormatterFullQuébec
,并将其保留。
ZoneId
同样,您可以保留ZoneId
时区对象的缓存。
以continent/region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用诸如EST
或IST
之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
ZoneId zoneMontréal = ZoneId.of( "America/Montreal" ) ;
然后随时使用它们,甚至跨线程。
ZonedDateTime zdt = ZonedDateTime.now( zoneMontréal ) ;
String output = zdt.format( dateTimeFormatterFullQuébec ) ;
dimanche 4 mars2018à18:36:32东部标准时间
java.time 对象(例如ZonedDateTime
和Instant
)也是不可变且线程安全的,就像ZoneId
& DateTimeFormatter
。您可以缓存所有这些,并在线程中使用它们。
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和& SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 2 :(得分:2)
你应该对这样的事情非常小心。标准(简单)格式化程序不是线程安全的。我与一些共享/缓存的格式化程序遇到了一些多线程相关的问题,但那是几年前(Java 1.4)。如果您检查JavaDocs(SimpleDateFormat),您会注意到以下内容:
同步
日期格式未同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问格式,则必须在外部进行同步。