这是一段代码
public Map<String,Object> findTruckParts(Map<String,Object> output){
Map<String,Object>findPartsMap = null;
NewFooInstance newFooInstance = new NewFooInstance();
findPartsMap = PartBuilder.buildPartsOutputMap(output, outputMap);
newFooInstance.buildItem(findPartsMap);
return findPartsMap;
}
outputMap是一个新的hashMap,输出是带有一些备件信息的hashmap。 buildItem调用一些遍历findPartsMap的其他私有方法。
public class NewFooInstance{
buildItem(Map<String,Object> partsMap){
checkPartsValidity(partsMap, fetchMapOfValidParts());
}
checkPartsValidity(Map<String,Object> partsMap,Map<String,Object> partsMap){
//partsMap = update partsMap with missing items fetched from list of valid parts
}
}
以上线程安全吗?由于所有映射都是各自方法的本地映射,因此我的假设是这是线程安全的。
编辑:我稍微修改了一下这个方法。接收地图并返回另一个地图。所以,我的问题是,这个被返回的地图是线程安全的吗?它是方法的本地,所以我认为这将是线程安全的(没有其他线程进入将能够更改其值,以防这个地图失去其监视器),但是,因为这个地图正在其他类和其他方法中被修改,这个方法 - 这个地图的本地性是否跨越不同的类/方法并确保线程安全?
答案 0 :(得分:1)
答案是“不”,因为HashMap
本身不是线程安全的。 考虑使用线程安全的Map实现,例如ConcurrentHashMap。
答案 1 :(得分:1)
问题在于:
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:在线程“Thread-1”中启动异常 java.util.ConcurrentModificationException at java.util.HashMap $ HashIterator.nextEntry(HashMap.java:793)at at java.util.HashMap $ KeyIterator.next(HashMap.java:828)at 在Test $ 1.run(Test.java:12)测试$ 1.findTruckParts(Test.java:19)at 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)
我希望这会有所帮助。