Java 8はコンカレントコンピューティングに関する多くのユーティリティを提供していると聞きました。したがって、指定されたforループを並列化する最も簡単な方法は何ですか?
public static void main(String[] args)
{
Set<Server> servers = getServers();
Map<String, String> serverData = new ConcurrentHashMap<>();
for (Server server : servers)
{
String serverId = server.getIdentifier();
String data = server.fetchData();
serverData.put(serverId, data);
}
}
streams を読んで、彼らはすべて新しい怒りです。
並列処理に関するビットには特に細心の注意を払ってください。
「明示的なforループを使用した要素の処理は本質的にシリアルです。ストリームは、個々の要素に対する命令型演算としてではなく、集計演算のパイプラインとして計算を再フレーミングすることにより、並列実行を容易にします。すべてのストリーム演算は、シリアルまたはパラレルで実行できます。 」
要約すると、並列forループはなく、本質的に直列です。ただし、Streamsがジョブを実行できます。次のコードを見てください。
Set<Server> servers = getServers();
Map<String, String> serverData = new ConcurrentHashMap<>();
servers.parallelStream().forEach((server) -> {
serverData.put(server.getIdentifier(), server.fetchData());
});
それはStream
を使用します:
servers.parallelStream().forEach(server -> {
serverData.put(server.getIdentifier(), server.fetchData());
});
Collector
を使用すると、並行コレクションを使用するため、ここでより大きな効果が得られると思われます。
よりエレガントで機能的なソリューションは、次の例のように、ConcurrentHashMapの別のステートフル変数を維持することを避けるために、コレクターのtoMapまたはtoConcurrentMap関数を使用することです。
final Set<Server> servers = getServers();
Map<String, String> serverData = servers.parallelStream().collect(
toConcurrentMap(Server::getIdentifier, Server::fetchData));
注:1.これらの機能インターフェース(Server::getIdentifier or Server::fetchData
)は、ここでチェック例外のスローを許可しません。2.並列ストリームの利点を最大限に活用するには、サーバーの数が多く、I/Oが関与しません。それらの関数での純粋なデータ処理(getIdentifier, fetchData
)
http://docs.Oracle.com/javase/8/docs/api/Java/util/stream/Collectors.html#toConcurrentMap のコレクターjavadocを参照してください。
コピーアンドペーストの簡単な例(上記の例では、OPによって記述されたカスタムクラスであるServer
クラスを使用しています):
import Java.io.Console;
import Java.util.ArrayList;
ArrayList<String> list = new ArrayList<>();
list.add("Item1");
list.add("Item2");
list.parallelStream().forEach((o) -> {
System.out.print(o);
});
コンソール出力。すべてが並行して実行されると、順序が変わる可能性があります。
Item1
Item2
.parallelStream()
メソッドはJava v8
で導入されました。この例は、JDK v1.8.0_181
でテストされました。