したがって、次のように、マップに入力するための並列ストリームを取得するリストがあります。
_Map<Integer, TreeNode> map = new HashMap<>();
List<NodeData> list = some_filled_list;
//Putting data from the list into the map
list.parallelStream().forEach(d -> {
TreeNode node = new TreeNode(d);
map.put(node.getId(), node);
});
//print out map
map.entrySet().stream().forEach(entry -> {
System.out.println("Processing node with ID = " + entry.getValue().getId());
});
_
このコードの問題は、「データのパッティング」プロセスがまだ進行しているときにマップが印刷されていることです(これは並列です)。そのため、マップはまだリストからすべての要素を受け取っていません。もちろん、実際のコードでは、マップを出力するだけではありません。 O(1)ルックアップ時間を利用するためにマップを使用します。
私の質問は:
メインスレッドを待機させて、マップが印刷される前に「プットデータ」が終了するようにする方法スレッドt内に「データを置く」ことを試み、t.start()
およびt.join()
を実行しようとしましたが、それは役に立ちません。
この場合、並列ストリームを使用することは想定されていませんか?リストは長く、並列処理を利用して効率を向上させたいだけです。
このlist.parallelStream().forEach
を使用すると、side-effects
プロパティは、Streamのドキュメントで明示的に述べられています。
また、このコードは、「データのパッティング」プロセスがまだ進行しているときにマップが印刷されていることを意味します(それは並列です)、forEach
端末操作であり、次の行のプロセスに進むことができるまで、終了を待機します。あなたはseeingかもしれません。スレッドセーフでないHashMap
に収集していて、一部のエントリがそのマップにない可能性があるためです...他の方法について考えてください。複数のスレッドからの複数のエントリをHashMap
に配置すると発生しますか?まあ、多くのものが壊れる可能性があります。たとえば、エントリが見つからない、マップが正しくない/矛盾しているなどです。
もちろん、スレッドセーフであるため、これをConcurrentHashMap
に変更しても機能しますが、「安全な」方法ではありますが、副作用プロパティに違反しています。
正しいことは、collect
なしで直接Map
をforEach
に直接変換することです。
Map<Integer, TreeNode> map = list.parallelStream()
.collect(Collectors.toMap(
NodeData::getId,
TreeNode::new
));
このように、並列処理であっても、すべてがうまくいきます。並列処理によって測定可能なパフォーマンスを向上させるにはlots(数万要素)が必要になることに注意してください。
ストリーム実装は、並列実装と並列実装ではない両方の処理が完了するまでブロックされます。
したがって、表示されるのはthe "putting data" process is still going on
ではありません。HashMap
はスレッドセーフではないため、おそらくデータの破損だけです。代わりにConcurrentHashMap
を使用してみてください。
ストリームがまだ処理されている可能性がある場合は、次のようなことを試すことができると思います:
List<NodeData> list = new ArrayList<>();
//Putting data from the list into the map
Map<Integer, TreeNode> map = list.parallelStream()
.collect(Collectors.toMap(
n -> n.getId(),
n -> new TreeNode(n)
));
少なくとも今、あなたはストリーム上にターミナルを持っています。可能な限り複数のスレッドを使用し、マッピングは確実に完了します。