Java8新機能 ラムダ式で並列処理

一昨日の記事で繰り返し処理をラムダ式で書きましたが、 ラムダ式のいいところは短くなるだけではなく、並列処理が出来るということらしいので朝一でやってみました。

まずは普通に

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
SimpleDateFormat DF = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
long start = System.currentTimeMillis();
for (int x : list) {
    try { Thread.sleep(1000); } catch(Exception e){}
    System.out.println(DF.format(new Date()) + ":" + x);
}
long end = System.currentTimeMillis();
System.out.println((end - start) + "ms");
出力結果
2013/05/29 09:28:37:1
2013/05/29 09:28:38:2
2013/05/29 09:28:39:3
2013/05/29 09:28:40:4
2013/05/29 09:28:41:5
5001ms

1つ出力するたびに1秒停止しているので、当然ながら5秒程度かかります。

ラムダ式で

start = System.currentTimeMillis();
list.forEach(x->{
    try { Thread.sleep(1000); } catch(Exception e){}
    System.out.println(DF.format(new Date()) + ":" + x);
});
end = System.currentTimeMillis();
System.out.println((end - start) + "ms");
出力結果
2013/05/29 09:28:42:1
2013/05/29 09:28:43:2
2013/05/29 09:28:44:3
2013/05/29 09:28:45:4
2013/05/29 09:28:46:5
5015ms

あれ、やっぱり5秒。全然並列処理になってない orz

並列処理のラムダ式で

Javadocを見てみたら、ListクラスにparallelStreamというメソッドがあったので使ってみると

System.out.println("---");
start = System.currentTimeMillis();
list.parallelStream().forEach(x->{
    try { Thread.sleep(1000); } catch(Exception e){}
    System.out.println(DF.format(new Date()) + ":" + x);
});
end = System.currentTimeMillis();
System.out.println((end - start) + "ms");
出力結果
2013/05/29 09:28:52:5
2013/05/29 09:28:52:2
2013/05/29 09:28:52:1
2013/05/29 09:28:53:4
2013/05/29 09:28:53:3
2005ms

無事並列処理になりました。
ただ、最初3個が同時に出力された後に残り2個が出力されるので、同時に3つまでしか並列処理されていないようです。この数はCPU数になるっぽいですね。
ちなみにparallelStreamの部分は

list.stream().parallel().forEach(~

でもOKです。

気になったこと

ここで使ってるSimpleDateFormatってスレッドセーフじゃないんですよねw
他にもArrayListとかHashMapとかStringBuilderとか、かなり使用頻度高いクラスも同様なので、並列処理にする時は気をつけましょう。