Вы верны. Если этот Map
может быть изменен несколькими потоками, возможно, что первый вызов chm.get(key)
вернет ненулевое значение, а второй вызов вернет null
(из-за удаления ключа из Map
, выполненного другим потоком) и таким образом, chm.get(key).doSomething()
будет бросать NullPointerException
.
Вы можете сделать этот код потокобезопасными, используя локальную переменную для хранения результата chm.get(key)
:
ConcurrentHashMap<Integer, Integer> chm = new ConcurrentHashMap<Integer, Integer>();
Integer value = chm.get(key);
if(value != null) {
value.doSomething(); // P.S. Integer class doesn't have a doSomething() method
// but I guess this is just an example of calling some arbitrary
// instance method
chm.remove(key);
}
BTW, даже если это Map
был не ConcurentHashMap
и только один поток имел доступ к нему, Я бы по-прежнему использовал локальную переменную, поскольку она более эффективна, чем вызов метода get()
дважды.
РЕДАКТИРОВАТЬ:
Как прокомментировал ниже, это исправление не помешает doSomething()
от вызова несколько раз для одной и того же ключа/значения разных потоков. Независимо от того, является ли это желаемым поведением, неясно.
Если вы хотите, чтобы возможность doSomething()
вызывалась несколькими потоками для одного и того же ключа/значения, вы можете использовать chm.remove(key)
для удаления ключа и получения значения на том же шаге.
Это, однако, рискует тем, что doSomething()
не будет выполняться вообще для какой-то ключ/значение, так как если первый вызов doSomething()
привело к исключению, не будет другой вызов doSomething()
другим потоком, так как пара ключей/значений больше не будет в Map
. С другой стороны, если вы удалите пару ключ/значение с Карты только после успешного выполнения doSomething()
, вы гарантируете, что doSomething()
будет успешно выполнен хотя бы один раз для всех пар ключ/значение, которые были повторно выпущены из Map
.
Возможно, даже лучше просто написать 'Integer value = chm.remove (key);' и удалить существующую строку 'chm.remove (key);' полностью. Таким образом, 'value' не лежит на карте, пока вы вызываете' doSomething() '. –
@ ErickG.Hagstrom Я не знаю, является ли проблема, что значение «лежит на карте, когда вы вызываете doSomething()». Возможно, требование состоит в том, чтобы удалить запись ключа/значения из Карты только после успешного выполнения doSomething. – Eran
Это не Threadsafe, 'doSomething' можно вызвать более одного раза. –