所以我有一个在类级别声明的哈希图,如下所示:
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();
}
}
为什么线程内部发生的映射更改在线程完成后不会保留?我已经贴花了地图静态和易失性...
提前致谢
为什么线程内部发生的映射更改在线程完成后不会保留?我已经宣布地图是静态和易失性的......
这在很大程度上取决于您更新地图的方式。
// update map here -- what's happening here?
正如@Louis指出的那样,如果多个线程正在更新同一个地图实例,volatile
对您没有帮助,您应该使用ConcurrentHashMap
。 正如@Gerhard所指出的,volatile
只是保护HashMap
引用的更新,而不是地图本身的内部。 如果线程并行更新映射或使用并发映射,则需要完全锁定映射。
但是,如果每个线程都用新映射替换映射,则 volatile
方法将起作用。 再说一次,由于争用条件,每个线程可能会覆盖中央映射。
如果您向我们展示您的更新代码,我们应该能够更好地解释它。
keyowrd 易失性仅使对所有线程可见的对 HashMap 的引用可见。
如果你想在多个线程中访问一个哈希映射,你需要使用同步映射。最简单的选择是使用 java.util.Hashtable
或使用 Collections.synchronizedMap(map)
.易失性声明在您的情况下是无用的,因为您的变量是在开始时初始化的。
volatile
的语义仅适用于要声明的变量。
在您的情况下,保存您对map
引用的变量是可变的,因此 JVM 将竭尽全力确保您对 map
包含的引用所做的更改对其他线程可见。
但是,map
引用的对象不受任何此类保证的约束,并且为了使其他线程查看对任何对象或任何对象图的更改,您需要建立先发生前关系。 对于可变状态对象,这通常意味着在锁上同步或使用专为并发而设计的线程安全对象。 令人高兴的是,在您的情况下,为并发访问设计的高性能Map实现是Java库的一部分:"ConcurrentHashMap"。