2013-07-12 4 views
4

Самый простой способ получить синхронизированную версию java.util.Set будет использовать Collections.synchronizedSet() так:Является ли конструктор-копия синхронизированной сетки безопасной?

Set mySyncSet = Collections.synchronizedSet(new HashSet()); 

Java API говорит об этом новом объекте, который:

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

Мой вопрос, если я создаю копию этого Set используя конструктор копирования, как это:

Set mySetCopy = new HashMap(mySyncSet); 

Wil это поточно-? (Не HashMap конструктор с помощью итерации, чтобы получить членов Set в конце концов?) Или я должен вручную синхронизировать работу, как это ?:

Set mySetCopy; 

synchronized(mySyncSet) { 
    mySetCopy = new HashMap(mySyncSet); 
} 
+2

'Collections.synchronized *()' почти полностью бесполезен и не должен использоваться. – SLaks

+0

http://stackoverflow.com/a/12182099/34397 – SLaks

+4

@SLaks Я не согласен с тем, что встроенные в синхронизацию коллекции Java полностью бесполезны. Это зависит только от необходимой вам гранулярности (или предпочитает). – RudolphEst

ответ

9

Давайте посмотрим на код:

public HashSet(Collection<? extends E> c) { 
    map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); 
    addAll(c); 
} 

Так что просто вызывает addAll,

public boolean addAll(Collection<? extends E> c) { 
    boolean modified = false; 
    for (E e : c) 
     if (add(e)) 
      modified = true; 
    return modified; 
} 

Так что петли над Collection вы даете ему.

Ответ поэтому нет, строительный экземпляр нет нить надежный.

Вам нужно использовать свой второй вариант и сделать явным synchronized на Set перед передачей его в конструктор.

0

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

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

+1

На самом деле, второй способ не помогает, если все остальные блокировки кода в одном экземпляре. – SLaks

+1

@SLaks согласился, я укажу это в своем ответе. Я использовал синхронизированные коллекции в реальных многопоточных приложениях (в основном, Swing GUI). Помимо штрафных санкций за блокировку вокруг reads/iterations, методы Collections.synchronized * полезны. Однако я бы рекомендовал более сложную систему блокировки/синхронизации для задач с ограничением производительности. – RudolphEst

+0

@ RudolphEst Я полностью согласен. Любая нетривиальная «синхронизация» может быть значительно улучшена с помощью 'Collection' в 'java.util.concurrent' или [' ReadWriteLock'] (http://docs.oracle.com/javase/1.5.0/документы/API/Java/Util/одновременные/замки/ReadWriteLock.html). Количество конфликтов, вызванных блокировкой 'Object' для доступа только для чтения, может быть огромным. –

Смежные вопросы