0

I'm looking at legacy code and found the following:

private static final SimpleDateFormat sdf = new SimpleDateFormat("...");
...
void foo() {
    bar(date, someMoreArgs, sdf.clone());
}

where bar() then goes ahead and uses the passed SimpleDateFormat to format the given date.

Is the above code thread-safe? If multiple threads concurrently call sdf.clone(), can one of the cloned objects end up getting corrupted?

I wouldn't write the code like that myself in the first place. I know there are better ways to do this. But I'm not looking to refactor the code unless it can be proven to be not thread-safe.

Edit:
Some more information for clarification:

  1. The static object sdf itself is never used for formatting. The only operation it's ever used for is cloning. Thus, I'm not expecting its contents to change (unless the cloning operation writes some transient data inside the object).

  2. The clone is never used by more than one thread.

DodgyCodeException
  • 5,289
  • 1
  • 11
  • 38
  • No. Any class or method from SimpleDateFormat are not thread safe. More info on why here : https://stackoverflow.com/questions/6840803/why-is-javas-simpledateformat-not-thread-safe – Shashaank V V Apr 24 '18 at 09:31
  • If using one instance it is not thread safe but he creates different instances for each thread to ensure thread safety – Veselin Davidov Apr 24 '18 at 09:32
  • 1
    AFAIK there’s nothing in the docs saying it should be thread-safe. On the other hand I’d immediately expect it to work in practice, but that’s certainly no guarantee. You may try it out with one or more threads eagerly cloning and testing the clones while another thread eagerly formats and/or parses, and see what you get. Not that this will guarantee thread-safety either, but maybe assure your lazines enough. :-) – Ole V.V. Apr 24 '18 at 09:34
  • And as you probably know I recommend you avoid the `SimpleDateFormat` class completely. It is not only long outdated, it is also notoriously troublesome. Today we have so much better in [`java.time`, the modern Java date and time API,](https://docs.oracle.com/javase/tutorial/datetime/) and it (thread-safe) `DateTimeFormatter`. If you end up not touching the code, fine. If you do refactor it, consider `java.time`. – Ole V.V. Apr 24 '18 at 09:36

3 Answers3

1

From the JavaDoc:

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.

So I believe that it depends on how you use that clone, but it is not assured. Cloning does not make your classes thread-safe. If the cloned object is not shared between class instances it should work with no problems, but I would not recommend this approach. However, you need a thread-safe date formatter I would suggest using Apache Commons FastDateFormat, described here.

Lorelorelore
  • 2,881
  • 6
  • 25
  • 32
1

Basically the clone() method doesn't give you thread safety. It just copies the properties of one object to another one. It doesn't lock or synchronize that object so if it is thread safe or not is up to the implementation. If during that copy some of the properties of the original object are changed then you might get into a strange state. If you use that cloned object in more than one threads - you still got problems

For your particular example I think the code is fine. The sdf object you are going to clone is probably never gonna change and you don't need a lock or something (it seems). You just create a new SimpleDateFormat object for each thread to ensure thread safety - or at least that's the idea - and you achieve that by using clone.

Anyway if you have spotted a problem in legacy code and you don't like it it is always better to spend some time and refactor it than to keep it like that even if you don't like it. It almost always pays off in the long term with having better and more maintainable code and not leaving that like that for the next developer to wander. For example if you have upgraded to java 8 you can use DateTimeFormatter which is thread safe or you can use some external library. Or at least create a new SimpleDateFormat(SOME_CONSTANT_FORMAT) everytime you need one instead of relying on clone of the object - because if you share just a string constant (the actual format) it is immutable and thread safe.

Veselin Davidov
  • 6,886
  • 1
  • 13
  • 21
1

This is not an answer. But some information you may still find interesting. I did a couple of experiments.

First I had two threads formatting dates using the same SimpleDateFormat instance. After a couple of iterations they began giving incorrect results, and after a few hundred iterations one of the threads crashed. So the thread-unsafety seems very real.

Next I had one thread format dates using the original SimpleDateFormat and the other one taking clones of it and using the clones for formatting. Both threads have run for several minutes now and are still both producing correct results.

This is by no means any guarantee that this is the behaviour you will always see. The documentation is pretty clear: SimpleDateFormat is not thread safe and all access from several threads must be synchronized. So use the information at your own risk.

EDIT: Inspecting the source code seems to reveal that the clone operation copies fields in some order, but doesn’t modify the original. If the original was doing any work in another thread, this might cause the clone to be in an inconsistent state after creation, which in turn might or might not affect its correct working. If the original is only used for cloning, I see no risk with the current implementation. As you say, the implementation may be changed in later Java versions, but I would consider the risk small, and the risk of thread-unsafe behaviour being introduced even smaller. All of this is pure speculation!

Ole V.V.
  • 65,573
  • 11
  • 96
  • 117
  • That's interesting - thanks! By the way, your tests are more likely to show a problem than the legacy code I'm looking at, in which the original static SimpleDateFormat object is never used for formatting - it's only ever used for cloning. If cloning is a strictly read-only operation, and does a *deep* clone, then this code is thread-safe. If cloning writes temporary data to the SimpleDateFormat object before taking the clone, then it's not thread-safe. I couldn't find any info or guarantee either way. (And I don't want to look at the API implementation as that's no guarantee it won't change.) – DodgyCodeException Apr 24 '18 at 11:04