Reputation: 15349
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?
Upvotes: 23
Views: 20690
Reputation: 26077
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
Using ThreadLocal
public static final ThreadLocal SIMPLE_DATE_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
Java 8, DateTimeFormatter
API
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
Upvotes: 0
Reputation: 11978
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);
Upvotes: 26
Reputation: 274738
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
Upvotes: 2
Reputation: 240928
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.
Upvotes: 31
Reputation: 81970
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?
Upvotes: -2