次のクラスを実行すると、ExecutionService はしばしばデッドロックします。
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorTest {
public static void main(final String[] args) throws InterruptedException {
final ExecutorService executor = Executors.newFixedThreadPool(10);
final HashMap<Object, Object> map = new HashMap<Object, Object>();
final Collection<Callable<Object>> actions = new ArrayList<Callable<Object>>();
int i = 0;
while (i++ < 1000) {
final Object o = new Object();
actions.add(new Callable<Object>() {
public Object call() throws Exception {
map.put(o, o);
return null;
}
});
actions.add(new Callable<Object>() {
public Object call() throws Exception {
map.put(new Object(), o);
return null;
}
});
actions.add(new Callable<Object>() {
public Object call() throws Exception {
for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
iterator.next();
}
return null;
}
});
}
executor.invokeAll(actions);
System.exit(0);
}
}
では、なぜこれが起こるのですか?またはさらに良いことに、カスタム抽象マップの実装がスレッドセーフであることを確認するテストを作成するにはどうすればよいでしょうか? (一部の実装には複数のマップがあり、別のデリゲートはキャッシュ実装など)
背景: これは Windows 上の Java 1.6.0_04 および 1.6.0_07 で発生します。問題が sun.misc.Unsafe.park() にあることはわかっています。
- Core2 Duo 2.4Ghz ラップトップで問題を再現できますが、デバッグ中には再現できません
- 作業中の Core2 Quad でデバッグできますが、RDP でハングアップしているため、明日までスタック トレースを取得できません。
以下のほとんどの回答は、HashMap のスレッド以外の安全性に関するものですが、HashMap にロックされたスレッドは見つかりませんでした。それはすべて ExecutionService コード (および Unsafe.park()) にありました。明日、スレッドを詳しく調べます。
これはすべて、カスタムの抽象 Map 実装がスレッドセーフではなかったためです。そのため、すべての実装がスレッドセーフであることを確認することにしました。本質的に、ConcurrentHashMap などの理解がまさに期待どおりであることを確認したいのですが、ExecutionService が奇妙に欠けていることがわかりました...