4

I want to do some formatting in my webapp, using MessageFormat, DateFormat, DecimalFormat, etc.

Since these are not thread-safe, one static instance for each usage won't work, but it seems wasteful to create a new XXXXFormat object each time one is needed. Caching and re-using them with a ThreadLocal seems like an obvious optimization.

This seems like a very common pattern, so I'm wondering if there are any appropriate libraries.

Instead of calling:

    DecimalFormat formatter = new DecimalFormat("###,##0.00");

    String formatted = formatter.format(value);             

every time I need to format something, why not:

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

where FormatCache would do the ThreadLocal caching with a HashMap keyed on the format pattern?

Presumably there'd be other methods like:

    String FormatCache.formatDecimal(String, Number);
    String FormatCache.formatDate(String, Date);
    String FormatCache.formatMessage(String, Object...);
Brad Tofel
  • 451
  • 4
  • 11

3 Answers3

5

Apache Commons Lang has FastDateFormat, which solves the problem the right way (in my opinion), by just being threadsafe to begin with:

FastDateFormat is a fast and thread-safe version of SimpleDateFormat.

This class can be used as a direct replacement to SimpleDateFormat in most formatting situations. This class is especially useful in multi-threaded server environments. SimpleDateFormat is not thread-safe in any JDK version, nor will it be as Sun have closed the bug/RFE.

Brendan Long
  • 53,280
  • 21
  • 146
  • 188
  • Definitely addresses the threading and caching part, but doesn't look like it will handle the non date formats. – Brad Tofel Aug 03 '12 at 20:24
5

tl;dr

Cache a thread-safe DateTimeFormatter object (immutable).

Never use SimpleDateFormat. Use only java.time package for date-time work.

java.time

The troublesome old date-time classes such as DateFormat & SimpleDateFormat are now supplanted by the modern java.time classes. Specifically here, the DateTimeFormatter class.

Immutable objects, thread-safe

The java.time classes were designed to be Immutable Objects. This means that rather than modifying any content in the object, a new distinct object is generated. The original is left intact.

This, and other techniques, make the java.time classes thread-safe by design and are so documented.

DateTimeFormatter

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

You can cache that object dateTimeFormatterFullQuébec, keep it around.

ZoneId

Likewise, you could keep a ZoneId time zone object cached.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

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

Then use them any time, even across threads.

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

dimanche 4 mars 2018 à 18:36:32 Eastern Standard Time

The java.time objects such as ZonedDateTime and Instant are also immutable and thread-safe, just like the ZoneId & DateTimeFormatter. You can cache all of these, and use them across threads.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
2

You should be really careful with something like that. The standard (simple) formaters are not threadsafe. I've ran into some multithread related issues with some shared/cached formaters, but that was some years ago (Java 1.4). If you check the JavaDocs (SimpleDateFormat), you will notice the following:

Synchronization

Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

Constantin
  • 61
  • 4
  • 1
    right - I was suggesting ThreadLocal for just this reason, but didn't explain the rationale. I've edited original post to clarify that this isn't the real question. – Brad Tofel Aug 06 '12 at 15:58