Making DateFormat Threadsafe. What to use, synchronized or Thread local

前端 未结 6 1527
甜味超标
甜味超标 2020-12-17 22:14

I want to make following code thread safe. What is the best way to achieve it?

private static final DateFormat DATE_FORMAT = DateFormat.getDateTimeInstance(         


        
相关标签:
6条回答
  • 2020-12-17 22:38

    Better, use: org.apache.commons.lang.time.FastDateFormat (is a fast and thread-safe version of SimpleDateFormat)

    0 讨论(0)
  • 2020-12-17 22:40

    Avoid the legacy date-time classes

    The troublesome old date-time classes bundled with the earliest versions of Java have been supplanted by the java.time classes. The java.time classes are thread-safe and use immutable objects.

    java.time

    Replace your formatter and date types with java.time types to automatically get thread-safety.

    Define your DateTimeFormatter globally if so desired. That class can automatically localize the string being generated, or you can specify a certain format.

    • Specify a FormatStyle to determine length of abbreviation.
    • Specify a Locale to determine (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, and such.
    • Specify a ZoneId for a time zone in which to adjust the moment.

    The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds. The ZonedDateTime class adjusts an Instant into a particular time zone.

    Your code, translated to java.time classes. In real work I would break this out into multiple lines, and would trap for exceptions.

    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ;
    private static final ZoneId ZONE_ID = ZoneId.of( "America/Montreal" );
    
    public static final String eventTypeToDateTimeString(long timestamp)
    {
       return Instant.ofEpochMilli( timestamp ).atZone( ZONE_ID ).format( DATE_TIME_FORMATTER );
    }
    

    Do not track date-time as count-from-epoch

    I do not advise passing around a long as a way of representing date-time values. Makes debugging and logging difficulty as a human cannot discern the meaning of the date-time value. Instead, pass around the java.time types such as Instant. Using the java.time types provides type-safety and makes your code more self-documenting.


    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?

    • Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
      • Java 9 adds some minor features and fixes.
    • Java SE 6 and Java SE 7
      • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
    • Android
      • Later versions of Android bundle implementations of the java.time classes.
      • For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

    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.

    0 讨论(0)
  • 2020-12-17 22:44

    There are several alternatives, with different trade-offs.

    You can synchronize access to a single DateFormat. This minimizes the number of formatter objects created, but different threads will have to contend for a lock before they can access the formatter. This is probably the worst alternative performance-wise; a lot of threads could end up spending time waiting, and the more threads you have the worse this will be.

    You can create a new DateFormat object for each use. That will eliminate contention between threads, but if there is a lot of date formatting you could put pressure on the garbage collector with this approach, and that will hurt performance. But this can work well enough in many cases and is very simple.

    A third alternative, making the DateFormat a threadlocal variable, is a lot more efficient. There is no contention between threads, and the formatter can be reused by a thread repeatedly, so it doesn't create nearly so much garbage. The downsides would be that it's the least straightforward approach, and any objects you put in a threadLocal may stick around longer than you want if you don't clear them out.

    0 讨论(0)
  • 2020-12-17 22:47

    The simplest solution would be:

    synchronized public static final String eventTypeToDateTimeString(long timestamp) {
      return DATE_FORMAT.format(new Date(timestamp));
    }
    

    No need to use ThreadLocals since this is all in a static context.

    0 讨论(0)
  • 2020-12-17 22:48

    You can

    1. Create a new DateFormat instance every time you need one.

    2. Use a synchronized block, as pointed by @Giovanni Botta.

    3. Use ThreadLocal:

      private static final ThreadLocal<DateFormat> THREADLOCAL_FORMAT =
          new ThreadLocal<DateFormat>() {
              @Override protected DateFormat initialValue() {
                  return DateFormat.getDateTimeInstance();
              }
          };
      
      public static final String eventTypeToDateTimeString(long timestamp) {
          return THREADLOCAL_FORMAT.get().format(new Date(timestamp));
      }
      

    Actually, using ThreadLocal might give you the best performance if you have a thread pool (meaning threads are reused), which most web containers do.

    Reference

    http://www.javacodegeeks.com/2010/07/java-best-practices-dateformat-in.html

    0 讨论(0)
  • 2020-12-17 22:54

    Just create a new copy on each call until it's actually demonstrated to be a performance problem. The overhead of manually managing thread-locals is likely to swamp any advantage you get from caching them.

    0 讨论(0)
提交回复
热议问题