同じことを実行しているスレッドを一時停止して、そのうちの1つが終了するのを待つことにより、並行プログラムを改善しています。ただし、スレッドを適切に起こすことはできません。これがコードです。
//to store graphs, if a thread finds the graph it is going to compute is in the entry, it waits, otherwise it compute then notify all other threads waiting on it.
Map<Graph, Object> entry = new ConcurrentHashMap<Graph, Object>();
public Result recursiveMethod(Graph g) {
if (entry.get(g) != null) {//if the graph is in the entry, waits
synchronized(entry.get(g)) {
entry.get(g).wait();
}
//wakes up, and directly return the result
return result;
}
synchronized(entry) {
if (entry.get(g) == null)//if the graph is not in the entry, continue to compute
entry.put(g,new Object());
}
//compute the graph recursively calls this method itself...
calculate here...
//wake up threads waiting on it, and remove the graph from entry
synchronized(entry.get(g)){
entry.get(g).notifyAll();
}
entry.remove(g);
return result;
}
このメソッドは、多数のスレッドによって呼び出されます。スレッドは、計算を開始する前に、エントリを調べて、同じグラフを計算している別のスレッドがあるかどうかを確認します。もしそうなら、それは待っています。そうでない場合は、計算を続行します。結果を把握した後、待機しているすべてのスレッドに通知します。
マップを使用して、グラフとオブジェクトをペアにします。オブジェクトはロックです。このマップは 2 つの同一のグラフを認識できることに注意してください。つまり、次のコードは true を返します。
Graph g = new Graph();
entry.put(g, new Object());
Graph copy = new Graph(g);
entry.get(g) == entry.get(copy) //this is true
したがって、entry.get(g) はロック/モニターとして問題ないはずです。ただし、ほとんどのスレッドは起動されておらず、3 ~ 4 個のスレッドのみが起動されています。待機しているスレッドの数がコンピューターが作成できるスレッドの数と等しい場合、つまりすべてのスレッドが待機している場合、このプログラムは決して終了しません。
entry.get(g).notifyAll() が機能しないのはなぜですか?