运行以下类时,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 奇怪地缺乏......