用于证明hashMap是故障安全的代码

时间:2012-04-18 09:05:48

标签: java collections

问题编辑:
HashSet和HashMap是快速失败的(但不是gauranteed),如代码中所述:

void goHashSet() {
        Set set = new HashSet();
        for (int i = 1; i <= 10; i++) {
            set.add(i);
        }
        Iterator i = set.iterator();
        while (i.hasNext()) {
            // set.add(16);//Exception in thread "main"
            // java.util.ConcurrentModificationException
            System.out.println("HashSet >>> itertor >>>" + i.next());
        }
    }

现在,我想要示例和故障安全的集合 我所知道的:ConcurrentHashMap,CopyOnWriteArrayList是故障安全的......但如何对其进行编码以证明它们是故障安全的

根据我的需求进行编辑和取消,以及如何实现目标:

如果我们使用HashMap

void goHashMap() {
        Map mp = new HashMap();
        for (int i = 19; i <= 24; i++) {
            mp.put(i, "x");
        }
        Set setKeys = mp.keySet();
        Iterator i = setKeys.iterator();
        while (i.hasNext()) {
            // mp.put(499, "x");// Exception in thread "main"
            // java.util.ConcurrentModificationException
            System.out.println("HashMap >>> itertor >>>" + i.next());
        }
    }

我们得到ConcurrentMException

但使用ConcurrentHashMap完成相同的代码,没有错误(非多线程环境)

void goConcurrentHashMap() {
    Map mp = new ConcurrentHashMap();
    for (int i = 19; i <= 24; i++) {
        mp.put(i, "x");
    }
    Set setKeys = mp.keySet();
    Iterator i = setKeys.iterator();
    while (i.hasNext()) {
        mp.put(499, "x");
        System.out.println("HashConcurrentMap >>> itertor >>>" + i.next());
    }
}

更多:在多线程环境中,ConcurrentHashmap可能会失败并抛出异常CME

3 个答案:

答案 0 :(得分:2)

HashMap不是 guarenteed 是安全的。您仍然可以在不同的线程中修改HashMap,并且不会注意到另一个线程。 OpenJDK版本的HashMap使用非volatile modcount字段来标识并发修改。由于非易失性字段不保证在线程之间保持一致,因此一个线程可以更改此设置,另一个线程无法注意到它已更改。

这是一种相对罕见的竞争条件,因此很有可能会检测到CME,但即使您测试它并且它的行为与预期连续10000次,这也不能提供您可能的证据。寻找。

实际上它可以编写代码,它将通过前10000次并在此之后一直失败。这是因为HotSpot编译将在此之后编译为本机代码。这意味着在优化之前运行正常的代码在优化后可能会有不同的行为。 esp表示非易失性字段。

答案 1 :(得分:1)

API Javadoc(适用于HashSetHashMap)仅对故障安全提供了软保证:

  

请注意,迭代器的快速失败行为无法得到保证,因为一般来说,在存在非同步并发修改的情况下,不可能做出任何硬性保证。失败快速的迭代器会尽最大努力抛出ConcurrentModificationException。因此,编写依赖于此异常的程序以确保其正确性是错误的:迭代器的故障快速行为应仅用于检测错误

HashSet在内部HashMap之上实现java.util.concurrent这一事实解释了相同的行为。

请随时查看与JDK安装捆绑在一起的源代码。

更新

  

现在,我想要示例和故障安全的集合

查看{{1}}包中的馆藏。

  

尽我所知:ConcurrentHashMap,CopyOnWriteArrayList是故障安全的......但是如何对其进行编码以表明它们是故障安全的

并发的本质是单独通过测试来证明线程安全(或失败安全)是不可能的。您只能证明相反的情况,即特定类不是线程安全的(如果恰好是这种情况)。这正是使并发变得困难的原因。

最接近证明这些事情的是由一个或多个并发专家对相关代码进行彻底分析。一些静态分析工具也可以发现一些问题,但同样,一个干净的静态分析结果并不能保证。

答案 2 :(得分:0)

好像我们看到了ConcurrentHashMap的内部实现,非常清楚地提到它可以用于原始集合的克隆而不是原始集合。

因此,理想情况下,您的原始集合与初始集合相同...所以这样我们可以说ConcurrentHashMap避免了COncurrentModifcationException并且可以被称为故障安全。

我尝试通过创建一个测试程序来测试它,其中多个线程试图修改我的地图。我运行测试大约10次,甚至没有一次它抛出ConcurrentModification异常。

如果我们更详细地了解ConcurentHashMap的实现......我们会发现同步机制与普通的hashmap非常不同......因为CHM适用于算法分段锁。

相关问题