故障安全迭代器的逻辑是什么?

9
如果故障安全的迭代器创建一个单独的副本并在其上工作,那么它如何意识到对原始数据的任何更改呢?
public class concurrentHashMap {
    public static void main(String[] args) throws InterruptedException {
        MapCheck obj1 = new MapCheck();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                obj1.put();
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                obj1.iterte();
            }
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

class MapCheck {
    Map<Integer,String> map = new ConcurrentHashMap<>();
    {
        map.put(1, "pujan");
        map.put(2, "manish");
        map.put(3, "swati");
    }

    void iterte() throws InterruptedException {
        for (int key : map.keySet()) {
            Thread.sleep(2000);
            System.out.println(map.get(key));
        }
    }

    void put() throws InterruptedException{
        Thread.sleep(2000);
        map.put(1, "pujan1");
        map.put(2, "manish1");
        map.put(3, "swati1");
    }
}

输出结果如下:
pujan1
manish1
swati1
1个回答

13
没有所谓的“故障安全”迭代器在Java中。至少,Java SE规范没有定义这样的术语。因此,我建议您避免使用“故障安全”一词来描述Java迭代器。
我很清楚互联网上和Stack Overflow其他地方的各种文章都使用了“故障安全”这个术语,但它们的用法并不明确,很可能是错误的,或者至少是误导性的。我相信您被这样的文档误导了。
似乎你在某个地方读到过“故障安全”迭代器在单独的副本上工作。在你的例子中,你使用了一个ConcurrentHashMap,它确实有不是故障快速的迭代器。然而,CHM的迭代器并不操作副本。相反,它们具有由官方规范描述为弱一致性的语义。定义有点深奥,但基本上,这样的迭代器报告的任何元素都保证在某个时候存在于集合中。这种迭代器可能会反映迭代开始后对集合所做的更改,也可能不会反映。这就是为什么运行迭代器的线程看到由另一个线程进行的更改。(由于这些线程存在数据竞争,因此也可能可见一些或没有更改)。
另一个其迭代器不是故障快速的集合的例子是CopyOnWriteArrayList。该集合的迭代器操作快照,因此集合的任何后续更改永远不会通过迭代器可见。

为了完整起见,这里是从ArrayList规范中定义的快速失败迭代器的定义。Java中大多数其他(非并发)集合都有类似定义的快速失败迭代策略。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接