2

所以我有一个在类级别声明的 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();
        }
 }


为什么线程内部发生的映射更改在线程完成后不会持续存在?我已经将地图贴上了静态和易失性...

提前致谢

4

3 回答 3

3

为什么线程内部发生的映射更改在线程完成后不会持续存在?我已经将地图声明为静态和易失性......

这在很大程度上取决于您如何更新地图。

// update map here -- what's happening here?

正如@Louis 指出的那样,如果多个线程正在更新同一个地图实例,volatile对您没有帮助,您应该使用ConcurrentHashMap. 正如@Gerhard 指出的那样,volatile只是保护HashMap 参考的更新,而不是地图本身的内部。如果线程并行更新映射或使用并发映射,则需要完全锁定映射。

但是,如果每个线程都用新地图替换地图,那么该volatile方法将起作用。再说一次,每个线程都可能因为竞争条件而覆盖中央映射。

如果您向我们展示您的更新代码,我们应该能够更好地解释它。

于 2013-09-13T21:57:45.737 回答
1

apply的语义volatile仅适用于您声明的变量。

在您的情况下,保存您的引用的变量map是可变的,因此 JVM 将竭尽全力确保您对包含的引用所做的更改map对其他线程可见。

但是,所引用的对象map不受任何此类保证的覆盖,并且为了使其他线程查看对任何对象或任何对象图的更改,您将需要建立先发生关系。对于可变状态对象,这通常意味着在锁上同步或使用为并发设计的线程安全对象。幸运的是,在您的情况下,为并发访问设计的高性能 Map 实现是 Java 库的一部分:“ConcurrentHashMap”。

于 2013-09-13T23:16:20.907 回答
1

keyowrd volatile仅使对 HashMap 的引用对所有线程可见。

如果要在多个线程中访问 HashMap,则需要使用同步映射。最简单的选择是 usingjava.util.Hashtable或 using Collections.synchronizedMap(map)volatile声明在您的情况下是无用的,因为您的变量是在开始时初始化的。

于 2013-09-13T21:59:28.770 回答