Looking for a proper fix of my code for S2885 ("Non-thread-safe fields should not be static")

I have a situation of code like the following:

class Test {
   private static final DateFormat TIMEFORMAT = new SimpleDateFormat("...");

   public static void writeLine(Date when,String foo) {
       System.out.println( TIMEFORMAT.format(when)+": "+foo);
   }
}

Some aspects can be attributed to the shortening of the example, but the
relevant ones are the static DateFormat, which (according to rule S2885) shouldn’t be
static, and the static method writeLine that uses this variable.

If I make TIMEFORMAT non-static I couldn’t use it from the static method, and
if I moved the creation of the SimpleDateFormat instance into the method, it
would be a waste of cpu-cycles.

Do i miss other alternatives? (Java 8 here, in case it matters.)
(it’s a method called from infinite(counted twice) places, so changing all
to new java.time classes is not really an option.

Hello @avl,

Looking at SimpleDateFormat (Java Platform SE 8 ) you can verify that it is not thread-safe:

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.

It is recommended to use DateTimeFormatter (Java Platform SE 8 ) to be thread-safe instead; this way, you can have it as static. Another approach to safely use DateFormat objects in a multi-threaded environment is to use a ThreadLocal (Java Platform SE 8 ) variable to hold the DateFormat object.

If you fail to solve this issue, you may have unexpected behavior. Have a look at this Stack Overflow post for examples of possible errors.

I hope this answers your concern and helps you to avoid bugs.

Cheers,
Angelo

2 Likes

I found another post here to a similar topic, where the author put all access to the static DateFormat(or other class with same issue) field inside “synchronized” blocks, and still got that error… The response was that they would fix it - that was a few years ago. synchronizing all usage of the DateFormat still didn’t help.

In the meantime I traded this bug for performance and re-create the DateFormat on each use.