Java ConcurrentHashSet-在多线程环境中对其进行迭代

时间:2019-05-12 13:31:06

标签: java multithreading java.util.concurrent concurrenthashmap

我已经看到了SynchronizedList的用例-他们声明,在进行迭代时,即使SynchronizedList是线程安全的,我们也应该像这样使用迭代器和同步块-

    synchronized(myList){
    Iterator<Item> iterator = myList.iterator();
    while (iterator.hasNext())
    {
        System.out.println(iterator.next().getMessage());
    }
    }

例如,如果我使用ConcurrentHashSet(在Java 8中可以使用并发HashMap的newKeySet()),那么在多线程环境中,是否仍然需要提取迭代器并使用同步块?我尝试对其进行测试,似乎没有必要,但是我可能会遗漏一些东西。

谢谢!

2 个答案:

答案 0 :(得分:2)

据我所知-从ConcurrentHashMap获得的每个迭代器都设计为由单个线程使用,并且不应传递。

如果您尝试同时使用多个线程迭代Map,除非每个线程都使用自己的迭代器,否则它将无法按预期工作。

带有迭代器的ConcurrentHashMap的并发是指您要在迭代时尝试从映射中放置或删除值的情况-这样将是线程安全的。 尽管不能保证另一个线程会看到更改,除非它正在从映射中获取新的迭代器。

我希望这些信息有用!

答案 1 :(得分:1)

ConcurrentHashMap.newKeySet()返回:

    /**
     * Creates a new {@link Set} backed by a ConcurrentHashMap
     * from the given type to {@code Boolean.TRUE}.
     *
     * @param <K> the element type of the returned set
     * @return the new set
     * @since 1.8
     */
    public static <K> KeySetView<K,Boolean> newKeySet() {
        return new KeySetView<K,Boolean>
            (new ConcurrentHashMap<K,Boolean>(), Boolean.TRUE);
    }
如您所见,

由ConcurrentHashMap支持。您可以使用返回的实例,而无需任何同步。

.iterator()方法返回一个新的KeyIterator,它由地图的Node<K,V>[] table

支持

因此,如果您在一个特定的线程中进行迭代,这意味着您将看到Node数组的快照,并且处于正确状态bc Node的每个节点内部都有易失链接,但是您的机率最低将会看到添加到原始地图的新元素,因为链接迭代器点是可变的。换句话说,您只是遍历一个数组而没有任何保证,如果该元素仍然存在于原始map atm中或在其中添加了一些新元素,但是您可以看到每个节点的最新状态bc:

    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        volatile V val;
        volatile Node<K,V> next;

key是最终的

val易失