#導入
こんにちは。けちょんです。
皆さん、SimpleDateFormatとstream使っていますか?
ニッチですね。私はstreamが大好きです。
今回はSimpleDateFormatがスレッドアンセーフであることを検証します。
#準備
まず、Date型のオブジェクトを用意します。
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
Calendar day1 = Calendar.getInstance();
day1.set(2020, 0, 31, 0, 0, 0);
Calendar day2 = Calendar.getInstance();
day2.set(1995, 3, 6, 0, 0, 0);
では、リストに詰めます。
for (int i = 0; i < 10; i++) {
// リストにDateオブジェクトを20個詰める
list.add(day1.getTime());
list.add(day2.getTime());
}
まずは並列実行せずに、処理します。
list.stream().map(date -> sdf.format(date)).forEach(System.out::println);
// 各要素を順にStringに変換し、出力
全貌は以下です。
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
Calendar day1 = Calendar.getInstance();
day1.set(2020, 0, 31, 0, 0, 0);
Calendar day2 = Calendar.getInstance();
day2.set(1995, 3, 6, 0, 0, 0);
List<Date> list = new ArrayList<>(); // リストの作成
for (int i = 0; i < 10; i++) {
// リストにDateオブジェクトを詰める
list.add(day1.getTime());
list.add(day2.getTime());
}
list.stream().map(date -> sdf.format(date)).forEach(System.out::println);
#シングルスレッドで実行
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
問題無さそうですね。
#マルチスレッドで実行
streamはparallel()を中間操作に追加するだけで、並列処理してくれます。
list.stream().map(date -> sdf.format(date)).forEach(System.out::println);
では実行してみましょう!
2020/01/31 12:00:00
1995/01/31 12:00:00 // なにこれ
1995/04/06 12:00:00
2020/01/31 12:00:00
2020/01/31 12:00:00
2020/01/31 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/31 12:00:00 // なにこれ
想定外の日付が一部出力されましたね。
スレッドアンセーフであることが確認できました。
#対策
各スレッドで、SimpleDateFormatオブジェクトを生成しても良いです。
基本的にはJava8から実装されたDate And Time APIを使用するのが良いでしょう。
##DateTimeFormatterを使用した実装
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm:ss");
LocalDateTime today = LocalDateTime.now();
LocalDateTime birthDay = LocalDateTime.of(1995, 4, 6, 12, 0, 0);
List<LocalDateTime> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
// リストにDateオブジェクトを詰める
list.add(today);
list.add(birthDay);
}
list.stream().parallel().map(date -> dtf.format(date)).forEach(System.out::println);
2020/01/31 09:33:20
1995/04/06 12:00:00
1995/04/06 12:00:00
2020/01/31 09:33:20
1995/04/06 12:00:00
2020/01/31 09:33:20
2020/01/31 09:33:20
2020/01/31 09:33:20
2020/01/31 09:33:20
2020/01/31 09:33:20
2020/01/31 09:33:20
1995/04/06 12:00:00
1995/04/06 12:00:00
1995/04/06 12:00:00
1995/04/06 12:00:00
1995/04/06 12:00:00
2020/01/31 09:33:20
2020/01/31 09:33:20
1995/04/06 12:00:00
1995/04/06 12:00:00
大丈夫そうですね。
#まとめ
Java8以降はDate And Time APIを使用しましょう