Гарантируется ли итерация через Collections.synchronizedSet (…) .forEach () поточно-ориентированной?

Как мы знаем, перебор параллельной коллекции не является потокобезопасным по умолчанию, поэтому нельзя использовать:

Set<E> set = Collections.synchronizedSet(new HashSet<>());
//fill with data
for (E e : set) {
    process(e);
}

Это происходит потому, что данные могут быть добавлены во время итерации, потому что нет эксклюзивной блокировки наset.

Это описать вJavadoc изCollections.synchronizedSet:

общедоступный статический Set synchronizedSet (Set s)

Возвращает синхронизированный (потокобезопасный) набор, поддерживаемый указанным набором. Чтобы гарантировать последовательный доступ, очень важно, чтобы весь доступ к вспомогательному набору осуществлялся через возвращенный набор.

Крайне важно, чтобы пользователь вручную синхронизировал возвращаемый набор при его итерации:

Set s = Collections.synchronizedSet (new HashSet ());
...
synchronized (s) { Iterator i = s.iterator(); // Must be in the synchronized block while (i.hasNext()) foo(i.next()); }

Несоблюдение этого совета может привести к недетерминированному поведению.

тем не мениеэто не относится кSet.forEach, который наследует метод по умолчаниюforEach отIterable.forEach.

Теперь я посмотрел исходный код, и здесь мы можем видеть, что у нас есть следующая структура:

Мы просимCollections.synchronizedSet().

Мы получаем один:

public static <T> Set<T> synchronizedSet(Set<T> s) {
    return new SynchronizedSet<>(s);
}

...

static class SynchronizedSet<E>
      extends SynchronizedCollection<E>
      implements Set<E> {
    private static final long serialVersionUID = 487447009682186044L;

    SynchronizedSet(Set<E> s) {
        super(s);
    }
    SynchronizedSet(Set<E> s, Object mutex) {
        super(s, mutex);
    }

    public boolean equals(Object o) {
        if (this == o)
            return true;
        synchronized (mutex) {return c.equals(o);}
    }
    public int hashCode() {
        synchronized (mutex) {return c.hashCode();}
    }
}

РасширяетсяSynchronizedCollection, который имеет следующееинтересно методы рядом с очевидными:

// Override default methods in Collection
@Override
public void forEach(Consumer<? super E> consumer) {
    synchronized (mutex) {c.forEach(consumer);}
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
    synchronized (mutex) {return c.removeIf(filter);}
}
@Override
public Spliterator<E> spliterator() {
    return c.spliterator(); // Must be manually synched by user!
}
@Override
public Stream<E> stream() {
    return c.stream(); // Must be manually synched by user!
}
@Override
public Stream<E> parallelStream() {
    return c.parallelStream(); // Must be manually synched by user!
}

mutex здесь используется тот же объект, к которомувсе операцииCollections.synchronizedSet Блокировка

Теперь мы можем, судя пореализация сказать, что это потокобезопасное использованиеCollections.synchronizedSet(...).forEach(...), но это также потокобезопасныйпо спецификации?

(Достаточно запутанно,Collections.synchronizedSet(...).stream().forEach(...) являетсяне Потокобезопасен при реализации, и вердикт спецификации, кажется, также неизвестен.)

Ответы на вопрос(2)

Ваш ответ на вопрос