Являются ли методы ConcurrentHashMap compute, computeIfAbsent и computeIfPresent полностью атомными c? - PullRequest
2 голосов
/ 05 января 2020

Атоми вызова всего метода c или просто атомы выполнения BiFunction c? Это блокировка для всех клавиш или только для звонков на одну и ту же клавишу?

Ответы [ 2 ]

1 голос
/ 05 января 2020

Следующие сведения относятся к OpenJDK Java 11.

Эти три метода удерживают блокировку Node на карте во время вызова метода и обновления ключа / значения. Этот узел обычно будет первым узлом в цепочке или дереве узлов для корзины ha sh. Одновременные попытки вставить, обновить или удалить пары ключ / значение в одном и том же сегменте будут блокироваться до тех пор, пока не будет снята блокировка.

(Поведение для других версий Java может отличаться.)


Является ли весь вызов метода атомом c или просто атомом выполнения BiFunction c?

Весь вызов метода.

Блокируется ли он для всех клавиш или только для звонков на одну и ту же клавишу?

Где-то посередине; смотри выше. Но если вы будете следовать этому совету в javadocs , это не должно иметь значения.

"Некоторые попытки обновления этой карты другими потоками могут быть заблокированы во время вычисления в процессе , поэтому вычисление должно быть коротким и простым ... "

0 голосов
/ 05 января 2020

Я только что проверил это с Kotlin сопрограммами на Android, используя следующий код

val incrementalNum = AtomicInteger(0)
val map = ConcurrentHashMap<Int, Unit>()
val lastThreadNum = AtomicInteger(-1)
val collisions = AtomicInteger(0)

for (a in 0..1000) GlobalScope.launch {
    val threadNum = incrementalNum.incrementAndGet()
    map.compute(threadNum) { k, v-> lastThreadNum.set(threadNum); Unit.apply {
        Log.e("SLOW", "this operation will slow things")
        if (lastThreadNum.get() != threadNum) Log.e("COLLISION", "Collision Number: ${collisions.incrementAndGet()}")
    }}
}

С map.compute (threadNum) я получаю достаточное количество коллизий (около 10-30) каждый Когда я запускаю его, при использовании map.compute (1) я никогда не получаю никаких коллизий.

Это, кажется, указывает на то, что - по крайней мере на Android - функция ConcurrentHashMap.compute блокируется только ключом (который это довольно хорошее поведение для моего варианта использования)

Я попытаюсь проверить это с другими Java реализациями, если это стандартная / обычная реализация, вероятно, ее лучше документировать

...