Потокобезопасный способ предоставления keySet () - PullRequest
4 голосов
/ 17 января 2011

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

public MyClass {
  Map<String,String> map = // ...
  public final Set<String> keys() {
     // returns key set
  }
}

Теперь, если моя "карта" не является поточно-ориентированной, это небезопасно:

  public final Set<String> keys() {
     return map.keySet();
  }

А также нет:

  public final Set<String> keys() {
     return Collections.unmodifiableSet(map.keySet());
  }

Итак, мне нужно создать копию, например:

  public final Set<String> keys() {
     return new HashSet(map.keySet());
  }

Однако это тоже не кажется безопасным, потому что этот конструктор обходит элементы параметра и добавляет их к ним (). Поэтому во время этого копирования может возникнуть исключение ConcurrentModificationException.

Итак:

  public final Set<String> keys() {
     synchronized(map) {
       return new HashSet(map.keySet());
     }
  }

похоже на решение. Это выглядит правильно?

Ответы [ 5 ]

4 голосов
/ 17 января 2011

Это решение не особенно полезно, если вы не планируете синхронизировать на карте везде, где оно используется.Синхронизация на нем не мешает другим одновременно вызывать методы для него.Это только мешает им также синхронизироваться с ним.

Лучшее решение, по-видимому, просто использовать ConcurrentHashMap, во-первых, если вы знаете, что вам нужны параллельные операции размещения и удаления, когда кто-то может выполнять итерации.Если поведение параллелизма, которое предлагает этот класс, не то, что вам нужно, вам, вероятно, просто нужно использовать полностью синхронизированную карту.

3 голосов
/ 17 января 2011

Хороший вопрос.Я бы использовал библиотеку Google Guava.Более конкретно метод com.google.common.collect.ImmutableSet.copyOf(Collection<? extends E>).В документации сказано, что этот метод является потокобезопасным.

0 голосов
/ 25 октября 2013

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

   synchronized(threadSafeIteratorConcurrentMapObject) {

       Iterator<String> keyItr = threadSafeIteratorConcurrentMapObject.keyIterator();
       while(keyItr.hasNext()){
        // Do whatever
       }
   }

Если вы не возражаете против изменения коллекции во время итерации;концентрируясь только на снимке элементов во время создания итератора;тогда без блока синхронизации вы можете использовать keyItr.Который уже потокобезопасен;он не проходит через ConcurrentModificationException.

0 голосов
/ 17 января 2011

Другой вариант - использовать ConcurrentHashMap. Его keySet () является потокобезопасным, поэтому может не потребоваться синхронизация или получение копии.

0 голосов
/ 17 января 2011

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

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