SimpleDateFormatはスレッドセーフではない


タイトルの通り[SimpleDateFormat](https://docs.oracle.com/javase/jp/8/docs/api/java/text/SimpleDateFormat.html "SimpleDateFormat")はスレッドセーフではないことを確認してみた。
反対に[DateTimeFormatter](https://docs.oracle.com/javase/jp/8/docs/api/java/time/format/DateTimeFormatter.html "DateTimeFormatter")はスレッドセーフとのことなので書き方の違いも合わせて比較してみた。

### サンプルコード
マルチスレッドでの実行を想定して以下のコードを実行してみる。

```Java
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;

/**
 * {@link SimpleDateFormat}と{@link DateTimeFormatter}の比較
 */
public class CompareSample {

    private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ISO_DATE;

    public void execute() {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                String sdf = this.useSimpleDateFormat(2016, 11, 7);
                String dtf = this.useDateTimeFormatter(2016, 11, 7);
                System.out.println("SimpleDateFormat=" + sdf + ", DateTimeFormatter=" + dtf + ", equals=" + sdf.equals(dtf));
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                String sdf = this.useSimpleDateFormat(2017, 12, 17);
                String dtf = this.useDateTimeFormatter(2017, 12, 17);
                System.out.println("SimpleDateFormat=" + sdf + ", DateTimeFormatter=" + dtf + ", equals=" + sdf.equals(dtf));
            }
        });

        t1.start();
        t2.start();
    }

    private String useSimpleDateFormat(int year, int month, int date) {
        Calendar cal = Calendar.getInstance();
        cal.set(year, month - 1, date);
        return SIMPLE_DATE_FORMAT.format(cal.getTime());

    }

    private String useDateTimeFormatter(int year, int month, int date) {
        LocalDate localDate = LocalDate.of(year, month, date);
        return DATE_TIME_FORMATTER.format(localDate);
    }
}
```

```Java
import org.junit.Test;

/**
 * {@link CompareSample}のテスト
 */
public class CompareSampleTest {

    @Test
    public void testExecute() {
        CompareSample test = new CompareSample();
        test.execute();
    }

}
```

### 実行結果

どちらも「2016-11-07」または「2017-12-17」であればOKだが、
SimpleDateFormatはたまにおかしな値を返すことがわかる。

```実行結果
SimpleDateFormat=2017-12-17, DateTimeFormatter=2017-12-17, equals=true
SimpleDateFormat=2016-11-07, DateTimeFormatter=2016-11-07, equals=true
SimpleDateFormat=2016-11-07, DateTimeFormatter=2016-11-07, equals=true
SimpleDateFormat=2017-11-07, DateTimeFormatter=2017-12-17, equals=false
SimpleDateFormat=2016-11-17, DateTimeFormatter=2016-11-07, equals=false
SimpleDateFormat=2017-12-17, DateTimeFormatter=2017-12-17, equals=true
SimpleDateFormat=2016-11-17, DateTimeFormatter=2016-11-07, equals=false
SimpleDateFormat=2017-12-17, DateTimeFormatter=2017-12-17, equals=true
SimpleDateFormat=2017-12-17, DateTimeFormatter=2017-12-17, equals=true
SimpleDateFormat=2016-11-17, DateTimeFormatter=2016-11-07, equals=false
SimpleDateFormat=2017-12-17, DateTimeFormatter=2017-12-17, equals=true
SimpleDateFormat=2016-11-07, DateTimeFormatter=2016-11-07, equals=true
SimpleDateFormat=2016-11-07, DateTimeFormatter=2016-11-07, equals=true
SimpleDateFormat=2017-12-17, DateTimeFormatter=2017-12-17, equals=true
SimpleDateFormat=2016-11-07, DateTimeFormatter=2016-11-07, equals=true
SimpleDateFormat=2017-12-17, DateTimeFormatter=2017-12-17, equals=true
SimpleDateFormat=2016-11-07, DateTimeFormatter=2016-11-07, equals=true
SimpleDateFormat=2017-12-17, DateTimeFormatter=2017-12-17, equals=true
SimpleDateFormat=2016-11-07, DateTimeFormatter=2016-11-07, equals=true
SimpleDateFormat=2017-12-17, DateTimeFormatter=2017-12-17, equals=true
```