所以我有一个在类级别声明的HashMap,如下所示:
private static volatile HashMap<String, ArrayList>String>> map =
new HashMap<String, ArrayList>String>>();
我有几个线程更新同一个地图,线程在类级别声明如下:
private class UpdateThread extends Thread {
@Override
public void run() {
// update map here
// map actually gets updated here
}
}
但是在线程退出后:
for (FetchSKUsThread thread : listOfThreads) {
thread.start();
}
for (FetchSKUsThread thread : listOfThreads) {
try {
thread.join();
// map not updated anymore :-[
} catch (InterruptedException e) {
e.printStackTrace();
}
}
为什么线程内部发生的地图更改在线程完成后不会持久存在?我已经对地图进行了静态和易变性处理......
提前致谢
答案 0 :(得分:3)
为什么线程内部发生的地图更改在线程完成后不会持续存在?我已经将地图声明为静态和易变...
这在很大程度上取决于您如何更新地图。
// update map here -- what's happening here?
正如@Louis所指出的,如果多个线程正在更新同一个地图实例,volatile
将无法帮助您,您应该使用ConcurrentHashMap
。正如@Gerhard指出的那样,volatile
仅保护HashMap
引用的更新,而不保护地图本身的内部。如果线程并行更新或使用并发映射,则需要完全锁定映射。
但是,如果每个线程用新地图替换地图,则volatile
方法将起作用。然后,由于竞争条件,每个线程可能会覆盖中央地图。
如果您向我们展示您的更新代码,我们应该能够更好地解释它。
答案 1 :(得分:1)
keyowrd volatile 仅使所有线程都可以看到HashMap的引用。
如果要在多个线程中访问HashMap,则需要使用同步映射。最简单的选择是使用java.util.Hashtable
或使用Collections.synchronizedMap(map)
。 volatile 声明在您的情况下是无用的,因为您的变量在开始时被初始化。
答案 2 :(得分:1)
volatile
的语义仅适用于您声明的变量。
在您的情况下,保存对map
的引用的变量是易失性的,因此JVM将竭尽全力确保您对map
包含的引用所做的更改对其他人可见线程。
但是,map
引用的对象不包含在任何此类保证中,并且为了更改任何对象或任何对象图形以供其他线程查看,您需要建立一个先发生过的事件。关系。对于可变状态对象,这通常意味着在锁上进行同步或使用为并发而设计的线程安全对象。令人高兴的是,在您的情况下,为并发访问而设计的高性能Map实现是Java库的一部分:`ConcurrentHashMap'。