Proof that SimpleDateFormat is not thread safe

I want to show my colleague that SimpleDateFormat is not thread safe with a simple JUnit test. The following class cannot do my question (reusing SimpleDateFormat in a multi-threaded environment), and I don't understand why. Can you determine what prevents my use of SDF to throw an exception at runtime?

public class SimpleDateFormatThreadTest { @Test public void test_SimpleDateFormat_MultiThreaded() throws ParseException{ Date aDate = (new SimpleDateFormat("dd/MM/yyyy").parse("31/12/1999")); DataFormatter callable = new DataFormatter(aDate); ExecutorService executor = Executors.newFixedThreadPool(1000); Collection<DataFormatter> callables = Collections.nCopies(1000, callable); try{ List<Future<String>> futures = executor.invokeAll(callables); for (Future f : futures){ try{ assertEquals("31/12/1999", (String) f.get()); } catch (ExecutionException e){ e.printStackTrace(); } } } catch (InterruptedException e){ e.printStackTrace(); } } } class DataFormatter implements Callable<String>{ static SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); Date date; DataFormatter(Date date){ this.date = date; } @Override public String call() throws RuntimeException{ try{ return sdf.format(date); } catch (RuntimeException e){ e.printStackTrace(); return "EXCEPTION"; } } } 
+4
source share
3 answers

The lack of thread safety does not necessarily mean that the code will throw an exception. Try viewing Andy Grove's article: SimpleDateFormat and thread safety ; he showed a lack of flow safety, showing that the output would not always be correct, given the different inputs.

When I run this code, I get the following output:

 java.lang.RuntimeException: date conversion failed after 3 iterations. Expected 14-Feb-2001 but got 01-Dec-2007 

Please note that “01-Dec-2007” is not even one of the lines in the test data. This is actually a combination of dates processed by two other threads!

+11
source

Isn't this part of the javadoc SimpleDateFormatter has enough evidence?

Synchronization

Date formats are not synchronized. It is recommended that you create separate format instances for each stream. If several threads access the format at the same time, it must be synchronized from the outside.

And the main thing to watch out for not being thread safe is to get unexpected results, not an exception.

+4
source

It is not thread safe due to this code in SimpleDateFormat (in Sun JVM 1.7.0_02):

 private StringBuffer format(Date date, StringBuffer toAppendTo, FieldDelegate delegate) { // Convert input date to time field list calendar.setTime(date); .... } 

Each format call stores the date in the calendar variable of the SimpleDateFormat member, and then applies the formatting to the contents of the calendar variable (and not the date parameter).

Thus, as each format call occurs, the data for all currently running formats can change (depending on the consistency model of your architecture) the data in the calendar member variable that is used by every other thread.

So, if you run several simultaneous calls in the format, you cannot get an exception, but each call can return the result obtained from the date of one of the other calls in the format, or a hybrid combination of data from different calls in the format.

+3
source

Source: https://habr.com/ru/post/1435520/


All Articles