【发布时间】:2009-07-01 09:27:32
【问题描述】:
在运行下面的类时,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 奇怪地缺乏......
【问题讨论】:
-
我明天的当前操作: 1. 仔细检查在 HashMap [resize] 代码中停止的线程 2. 升级到最新的 vm
-
在调整大小时不会停止任何线程 - 它们会调整大小并退出。检查线程卡在然后迭代 Callable。
标签: java concurrency hashmap