易失性HashMap不会在Thead之外更新

时间:2013-09-13 21:48:46

标签: java multithreading hashmap volatile

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


为什么线程内部发生的地图更改在线程完成后不会持久存在?我已经对地图进行了静态和易变性处理......

提前致谢

3 个答案:

答案 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'。