首页 > 解决方案 > Java ConcurrentHashSet - 在多线程环境中对其进行迭代

问题描述

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

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

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

谢谢!

标签: javamultithreadingjava.util.concurrentconcurrenthashmap

解决方案


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并且每个处于正确状态的节点 bcNode内部都有易失链接,但是您看到新元素添加到原始地图 bc 链接迭代器点的可能性最低不挥发。换句话说,您只是迭代一个数组,而没有任何保证该元素是否仍然存在于原始地图 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易变


推荐阅读