Can we declare SimpleDateFormat objects as static objects
Asked Answered
C

6

23
SimpleDateFormat monthFormat = new SimpleDateFormat("MMMM");
SimpleDateFormat fullFormat = new SimpleDateFormat("EE MMM dd, HH:mm:ss")

I have several such piece of code which gets invoked often, would it make sense to declare them as static variables?

Is it thread safe to pass dynamic arguments to the format() method in such cases?

Celom answered 26/5, 2011 at 11:9 Comment(0)
P
31

No they aren't thread-safe.Use Joda-time's version instead.

Or make them wrapped in synchronized method and make it thread-safe

Doc Says it clearly

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.

Prow answered 26/5, 2011 at 11:11 Comment(2)
synchronizing is, in my opinion, a very sub-optimal way. Critical sections should always be your last resort and only used for objects that must be both globally unique and thread-safe. Use ThreadLocal. The cost of creating SimpleDateFormat once for each new thread will reliably outweight the cost of synchronization, both in performance and complexity.Oppidan
Most Developers understand that for most classes that are not thread safe, that this is due to concurrently changing state. Once a Format is established, formatting a Date should not change state. Simply documenting this in official documentation as not thread-safe is not enough. It should be explicitly documented that even the format method is not thread-safe if it maintains temporary state in instance variables. Declaring it as static is not just a rookie mistake. Analogy can be made between modifying a collection (put) vs accessing a collection (get).Barbet
A
26

As of Java 8, this is supported in the new Date API. DateTimeFormatter is thread-safe and can do the same work as SimpleDateFormat. Cited from the JavaDoc:

A formatter created from a pattern can be used as many times as necessary, it is immutable and is thread-safe.

To be extra clear, it is perfectly fine to define a format such as:

private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");

And use it in methods that can be accessed by several threads concurrently:

String text = date.toString(formatter);
LocalDate date = LocalDate.parse(text, formatter);
Abstract answered 7/5, 2015 at 16:27 Comment(0)
H
2

DateFormat is not thread-safe. If multiple threads use the same DateFormat object without any synchronization you can get unexpected results. So you should either synchronize access to the DateFormat object, use a ThreadLocal variable or use an alternative Date API such as Joda-Time.

For more information on how to do this, take a look at this blog post: DateFormat with Multiple Threads

Hereby answered 26/5, 2011 at 11:22 Comment(0)
S
2

An alternative if you are already using Apache Commons:

https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/time/FastDateFormat.html

Sundowner answered 20/1, 2015 at 18:27 Comment(0)
S
0

SimpleDateFormat is simple in use, but yet complicated. Developer generally writes code and test as a single user, and succeeds. but in case of parallel and concurrent requests,SimpleDateFormat is a complicated dateformat.

having exposed as static in service or controller layer, and when multiple threads can access at same time, it can behave abnornally.

DateFormat APi class also recommends, "It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally."

code to demontsrate it's failure in multi threading environment.

public final class DateUtils {

    public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

    private DateUtils() {
    }

    public static Date parse(String target) throws ParseException {
        return DATE_FORMAT.parse(target);
    }

    public static String format(Date target) {
        return DATE_FORMAT.format(target);
    }

    private static void testSimpleDateFormatWithThreads() {
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        final String source = "2019-01-11";

        IntStream.rangeClosed(0, 20)
                .forEach((i) -> executorService.submit(() -> {
                    try {
                        System.out.println(DateUtils.parse(source));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }));

        executorService.shutdown();
    }

    public static void main(String[] args) {
        testSimpleDateFormatWithThreads();
    }
}

Output - This varies from machine to machine and will generate difefrent output how many time you run.

Wed Nov 11 00:00:00 IST 2201

Wed Nov 11 00:00:00 IST 2201

Fri Jan 11 00:00:00 IST 2019

Fri Jan 11 00:00:00 IST 2019

Fri Jan 11 00:00:00 IST 2019

Fri Jan 11 00:00:00 IST 2019

Fri Jan 11 00:00:00 IST 2019

Mon Dec 31 00:00:00 IST 2018

Fri Jan 11 00:00:00 IST 2019

Fri Jan 11 00:00:00 IST 2019

Fri Jan 11 00:00:00 IST 2019

Fri Jan 11 00:00:00 IST 2019

Fri Jan 11 00:00:00 IST 2019

Fri Jan 11 00:00:00 IST 2019

Fri Jan 11 00:00:00 IST 2019

Fri Jan 11 00:00:00 IST 2019

Fri Jan 11 00:00:00 IST 2019

Fri Jan 11 00:00:00 IST 2019

Sun Jan 11 00:00:00 IST 2201

Fri Jan 11 00:00:00 IST 2019

This breaks due to Calendar instance variable inside DateFormat -> SimpleDateFormat class.

Solution

  1. Using ThreadLocal

    public static final ThreadLocal SIMPLE_DATE_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));

  2. Java 8, DateTimeFormatter API

    public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

Sungsungari answered 23/5, 2022 at 18:16 Comment(0)
D
-2

static shouldn't be a problem.

Since AFAIK no guarantees are made about thread safety you'd have to check the source code for that. And even if you come to the conclusion that it is thread safe, this might change with the next release. As said in another answer they are not thread safe.

Do you really allocate such a huge amount of threads that giving each thread its own Format is a problem?

Darindaring answered 26/5, 2011 at 11:15 Comment(7)
The javadoc says that it isn't thread safe, so having it static is a big no no.Epigram
This could cause severe errors in business applications that rely on formatted date output. Probably dates could be mixed up, totally or partially. Therefore no good advice!Ephemeris
@user326120 What can mix up dates?Darindaring
@JensSchauder Concurrent access to DateFormat.format will return mixed dates, suppose DateFormat df = ...; Thread 1 comes in with df.format(d1), then Thread 2 comes in with df.format(d2), while Thread 1 is still executing df.format(d1). - The result cannot be predicted, since DateFormat is mutable, otherwise it would be thread-safe. (You could write a small test program, creating 10000 threads simultaneosly outputting formatted dates by one single instance of DateFormat, while dates have to vary in day (month) and year, so you can tell the "mixing". Explore it and tell us the result!)Ephemeris
@Andreas Krueger nobody is saying you should access it concurrently.Darindaring
How does making this field non-static fixes the thread safety issue? The instance variable is still can be accessed by other threads. Sonar also claims it is an issue.Luanneluanni
@Luanneluanni That is not what I wrote. I just wrote static isn't a problem, while thread safety is. Two orthogonal concernsDarindaring

© 2022 - 2024 — McMap. All rights reserved.