Одновременное изменение HashMap в Scala без актеров

Что я хочу сделать, так это начать с некоторой реализации Map и накапливать в ней данные путем итерации по параллельной коллекции. Ключи могут «перекрываться» между потоками, поскольку ключи генерируются вероятностно (связано с генерацией случайных чисел).

Бывший. Поток 1 хочет добавить ключ = значение = 1 на карту. Если он уже существует, добавьте 1 к существующему значению (поскольку значение равно 1), а если нет, создайте сопоставление. Тем временем другой поток имеет ключ = A и значение = 2 и хочет сделать то же самое.

Есть ли способ сделать это без создания всей системы Actor?

ConcurrentHashMap из библиотеки Java выглядит интересно, но «слабо согласованные» итераторы беспокоят меня в отношении безопасности обновления карты между потоками.


person adelbertc    schedule 16.07.2012    source источник
comment
Существуют и другие методы синхронизации... и все сводится к желаемым результатам/семантике.   -  person    schedule 16.07.2012
comment
Что касается итераторов ConcurrentHashMap, см.: stackoverflow.com/ вопросов/3768554/ Если эта семантика неверна, то что? Это похоже на выбор между READ COMMITTED, который разрешает неповторяющееся (в том числе фантомное) чтение, и SERIALIZABLE в транзакции БД.. что правильно?   -  person    schedule 16.07.2012


Ответы (1)


Это очень тривиальная вещь без Актеров.

class CountMap[K <: AnyRef](mapSize: Int = 16) extends ConcurrentHashMap[K, AtomicLong](mapSize) {
  def addCount(key: K): Long = (get(key) match { // Check value for key
    case null =>  // If not mapped yet
      val al = new AtomicLong(0) // Create a new memory slot to keep the count in that is thread safe
      putIfAbsent(key, al) match { // Try to put our memory slot in atomically
        case null => al // If we succeeded then our memory slot should be used
        case some => some // if there already was a memory slot, use that one
      }
    case some => some // If there already was a memory slot, use that one
    }).incrementAndGet() // increment and get the current value of the slot associated with the given key

  def getCount(key: K): Long = get(key) match { // get the memory slot associated with the key
    case null => 0L // if none, say it's 0
    case some => some.get() // if some get its value
  }
}
person Viktor Klang    schedule 16.07.2012
comment
Интересно - я предполагаю, что просто создам экземпляр этого и буду использовать его для изменения значений в потоках? - person adelbertc; 16.07.2012
comment
Я не согласен с тем, что это «очень тривиально». Это требует детального знания внутренней работы ConcurrentHashMap. Вероятно, существует гораздо больше неправильных (с ошибками) способов расширения такого класса, чем правильных способов. - person Rick-777; 18.07.2012
comment
Рик-777: Нужны подробные знания внутренней работы CHM. Все, что вам нужно знать, это то, что существует ConcurrentMap/AtomicLong и что вы можете читать JavaDoc. - person Viktor Klang; 18.07.2012