Java ConcurrentHashSet - итерация по нему в многопоточной среде - PullRequest
0 голосов
/ 12 мая 2019

Я видел варианты использования SynchronizedList - они утверждают, что после итерации, хотя SynchronizedList и является потокобезопасным, мы должны использовать итератор и синхронизированный блок, например:

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

Если я, например, использую ConcurrentHashSet (возможно в Java 8 с использованием newKeySet () concurrentHashMap), в многопоточной среде все еще необходимо извлекать итератор и использовать синхронизированный блок? Я попытался проверить это, и это кажется ненужным, но я мог что-то упустить.

Спасибо!

Ответы [ 2 ]

2 голосов
/ 12 мая 2019

Для того, что я знаю - каждый итератор, который вы получаете из ConcurrentHashMap, предназначен для использования одним потоком и не должен передаваться.

Если вы попытаетесь выполнить итерацию карты с несколькими потоками одновременно, она не будет работать должным образом, если каждый из потоков не использует свой собственный итератор.

Параллельный параллелизм ConcurrentHashMap ситератор ссылается на случаи, когда вы пытаетесь поместить или удалить значение из карты во время итерации - чем оно будет поточно-ориентированным.Хотя нет никакой гарантии, что другой поток увидит изменения, если он не получит новый итератор с карты.

Надеюсь, информация была полезной!

1 голос
/ 12 мая 2019

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 имеет изменчивые ссылки внутри, но существует минимальный шанс, что вы увидите новые элементы, добавленные к исходной карте, поскольку точки итератора ссылки не являются изменчивыми.Другими словами, вы просто выполняете итерацию по массиву без какой-либо гарантии, если этот элемент все еще существует в исходной карте 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 является изменчивым

...