0
0

More than 3 years have passed since last update.

SimpleDateFormatがスレッドアンセーフであることをstreamを使って検証する

Last updated at Posted at 2020-01-31

導入

こんにちは。けちょんです。
皆さん、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を使用しましょう

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0