1

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

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

4

3 回答 3

2

HashMap 不保证是故障安全的。您仍然可以在不同的线程中修改 HashMap 并且让另一个线程不会注意到。HashMap 的 OpenJDK 版本使用非volatilemodcount 字段来识别并发修改。由于非易失性字段不能保证在线程之间保持一致,一个线程可以更改它,而另一个线程无法注意到它的更改。

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

事实上,它有可能编写将通过前 10000 次并在此之后始终失败的代码。这是因为 HotSpot 编译将在此之后编译为本机代码。这意味着在优化之前运行良好的代码在优化后可能表现不同。尤其是非易失性领域。

于 2012-04-18T09:13:44.970 回答
1

API Javadoc(用于HashSetHashMap)仅对故障安全做出软保证:

请注意,不能保证迭代器的快速失败行为,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬保证。快速失败的迭代器ConcurrentModificationException在尽力而为的基础上抛出。因此,编写一个依赖于这个异常的正确性的程序是错误的:迭代器的快速失败行为应该只用于检测错误

HashSet相同的行为可以通过在内部实现的事实来解释HashMap

随意查看源代码,它与您的 JDK 安装捆绑在一起。

更新

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

看看java.util.concurrent包装中的收藏品。

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

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

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

于 2012-04-18T09:10:07.817 回答
0

就像我们看到 ConcurrentHashMap 的内部实现一样,它非常清楚地提到它适用于原始集合的克隆而不是原始集合。

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

I tried to test it by creating a test programs where multiple threads was trying to modify my map .. I ran the test around 10 times and not even a single time it throws ConcurrentModification exception.

If we go more in detail implementation of ConcurentHashMap ... we will find that the synchronization mechanism is very much different from normal hashmap ... as CHM works on the algorithm segmentation lock.

于 2013-04-13T11:47:49.940 回答