易失性哈希图不会在 Thead 之外更新



所以我有一个在类级别声明的哈希图,如下所示:

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"。

最新更新