並列処理怖いよって話
リストについて基本的に注意すべきですが、こと並列処理に関しては
マルチスレッドに要注意です
たとえば
だめ.java
private static List<String> list = new ArrayList<>();
private static Consumer<Integer> qwe = v -> list.add(String.format("%s: %s", Instant.now(), v));
public static void main(String[] args) {
IntStream.range(0, 9).boxed().collect(Collectors.toList()).parallelStream().forEach(qwe);
list.forEach(System.out::println);
}
これの結果は
null
null
null
2019-11-08T17:37:22.279Z: 7
2019-11-08T17:37:22.313Z: 3
2019-11-08T17:37:22.313Z: 0
2019-11-08T17:37:22.313Z: 4
2019-11-08T17:37:22.313Z: 6
2019-11-08T17:37:22.313Z: 8
とか
2019-11-08T17:37:48.381Z: 7
2019-11-08T17:37:48.381Z: 5
2019-11-08T17:37:48.381Z: 2
2019-11-08T17:37:48.416Z: 0
2019-11-08T17:37:48.416Z: 8
2019-11-08T17:37:48.417Z: 4
2019-11-08T17:37:48.417Z: 3
2019-11-08T17:37:48.417Z: 6
とか、もうめちゃくちゃです
なにnullってw
listにaddするタイミングで同時にやろうとして
よくわからんくなって障害起きてるわけですね
なので...
これでよし.java
private static List<String> list = Collections.synchronizedList(new ArrayList<>());
private static Consumer<Integer> qwe = v -> list.add(String.format("%s: %s", Instant.now(), v));
public static void main(String[] args) {
IntStream.range(0, 9).boxed().collect(Collectors.toList()).parallelStream().forEachOrdered(qwe);
list.forEach(System.out::println);
}
スレッドセーフなsynchronizedListを使い
かつ順番を整えるためにforEachorderedを使ってaddしました
ラムダのforEachは順次でやってくれているのでsysoutしてるとこはそのままで
2019-11-08T17:40:22.228Z: 0
2019-11-08T17:40:22.259Z: 1
2019-11-08T17:40:22.259Z: 2
2019-11-08T17:40:22.260Z: 3
2019-11-08T17:40:22.260Z: 4
2019-11-08T17:40:22.260Z: 5
2019-11-08T17:40:22.260Z: 6
2019-11-08T17:40:22.260Z: 7
2019-11-08T17:40:22.260Z: 8
って、綺麗にやってくれます
一言でいうと
同時に変更したらコンフリクトするやんけ!やめろ!ってことですね
注意しておけばスレッドセーフなものに切り替えるだけで良い感じでしょうか