问题在这里:
public Map<String,Object> findTruckParts(Map<String,Object> output)
尽管相对于结果映射在方法和子方法中看起来是线程安全的,但源映射(即“输出”)仍然存在线程安全问题。当您从中提取数据以放入新的结果映射时,如果它同时被另一个线程更改,您将获得一个ConcurrentModificationException
.
下面是一些代码来说明这个问题:
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception {
final Map<String, Object> test = new HashMap<String, Object>();
new Thread(new Runnable() {
public void run() {
System.out.println("Thread 1: started");
findTruckParts(test);
System.out.println("Thread 1: done");
}
public Map<String,Object> findTruckParts(Map<String,Object> output) {
Map<String, Object> result = new HashMap<String, Object>();
for(int i=0; i<100000000; i++) {
for(String key : output.keySet()) {
result.put("x", output.get(key));
}
}
return result;
}
}).start();
new Thread(new Runnable() {
public void run() {
System.out.println("Thread 2: started");
for(int i=0; i<100000; i++) {
test.put("y", "y"+i);
test.remove("y");
}
System.out.println("Thread 2: done");
}
}).start();
}
}
输出总是:
线程 1:已启动线程 2:在 java.util.HashMap$HashIterator.nextEntry(HashMap.java:793) 在 java.util.HashMap$KeyIterator.next(HashMap) 的线程“Thread-1”中启动异常 java.util.ConcurrentModificationException .java:828) 在 Test$1.findTruckParts(Test.java:19) 在 Test$1.run(Test.java:12) 在 java.lang.Thread.run(Thread.java:680) 线程 2:完成
因此,即使该findTruckParts()
方法创建了自己的映射来返回,如果它必须查看源映射并且其他一些线程正在修改它的键/值,就会出现问题。其他线程只是阅读,它不应该爆炸。但是我不确定您是否想在这种情况下谈论线程安全,因为它仍然不稳定。
帮助线程安全的一种方法是更改main
方法的第一行:
final ConcurrentHashMap<String, Object> test = new ConcurrentHashMap<String, Object>(new HashMap<String, Object>());
但是您可以看到安全要求是如何被推送给调用者的,这不是很好。因此,为了帮助实现这一点,您还可以更改方法的签名:
public Map<String,Object> findTruckParts(ConcurrentHashMap<String,Object> output);
现在有了线程安全。
因此,正如我在第一行所述,问题出在:
问题在这里:
public Map<String,Object> findTruckParts(Map<String,Object> output)
我希望这有帮助。