0

У меня есть ConcurrentMap, который мне нужно заполнить из многопоточного приложения. Моя карта приведена ниже:Как атомно обновить значение ConcurrentMap в многопоточном приложении?

private final ConcurrentMap<String, AtomicLongMap<String>> deviceErrorHolder = Maps.newConcurrentMap(); 

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

public void addDeviceErrorStats(String deviceName, String errorName) { 
    AtomicLongMap<String> errorMap = deviceErrorHolder.get(deviceName); 
    if (errorMap == null) { 
     errorMap = AtomicLongMap.create(); 
     AtomicLongMap<String> currenttErrorMap = deviceErrorHolder.putIfAbsent(deviceName, errorMap); 
     if (currenttErrorMap != null) { 
     errorMap = currenttErrorMap; 
     } 
    } 
    errorMap.incrementAndGet(errorName); 
    } 

Для каждого deviceName, у меня будет AtomicLongMap, который будет содержать все счетчики для различных errorName.

ExceptionCounter.getInstance().addDeviceErrorStats("deviceA", "errorA"); 
    ExceptionCounter.getInstance().addDeviceErrorStats("deviceA", "errorB"); 
    ExceptionCounter.getInstance().addDeviceErrorStats("deviceA", "errorC"); 

    ExceptionCounter.getInstance().addDeviceErrorStats("deviceB", "errorA"); 
    ExceptionCounter.getInstance().addDeviceErrorStats("deviceB", "errorB"); 

Is my addDeviceErrorStats метод потокобезопасный? А также способ корректировки значения моей deviceErrorHolder карты верны? Это будет атомная операция? Нужно ли мне синхронизировать создание новых экземпляров AtomicLongMap? Или CM позаботится обо мне?

Я работаю с Java7.

+0

Почему вы не пишете тестовый файл, чтобы сгенерировать сценарий и поделиться результатами: D –

+0

Вам нужно computeIfAbsent, чтобы сделать его потокобезопасным. –

+0

Я все еще на Java 7, поэтому не могу использовать 'computeIfAbsent' –

ответ

1

Вы можете создать лот более простую версию этого с computeIfAbsent().

AtomicLongMap<String> errorMap = deviceErrorHolder.computeIfAbsent(deviceName, a -> AtomicLongMap.create()); 
errorMap.incrementAndGet(errorName); 

computeIfAbsent (в параллельных картах) специально предназначена, чтобы сделать атомную версию того, что делает ваш нулевой проверки логики. Если ключ deviceName имеет значение, он возвращается, в противном случае вычисление называется атомарным, а возвращаемое значение вычисления одновременно связано с ключом на карте, а также возвращается.

+0

В чем проблема с моим кодом? Если есть проблема, то какой лучший способ сделать это в Java 7? –

+0

А, это отстой. Угадайте, что вам придется терпеть дополнительный код и несколько ненужных созданий объектов, которые есть в вашей версии. – Kayaman

+0

Итак, мой код все еще в порядке? Bcoz, как сказал Питер, может быть, это не потокобезопасность? –

0

Я считаю, что ваш метод верен. Предположим, что у нас есть два параллельных потока, вызывающих его для одного и того же устройства.

Случай, когда ошибка уже существует, тривиальна, так как оба потока получат то же самое и вызовут incrementAndGet на атоме.

Теперь давайте рассмотрим случай, когда errorMap не существует. скажем, что первый поток попадает в AtomicLongMap.create(), а затем запланирован второй поток. Такой поток также создаст собственную локальную карту. putIfAbsent() является атомарным, поэтому один из потоков возвращает null, а второй возвращает карту, помещенную первым. В последнем случае вы выбрасываете карту, созданную этим потоком, и используя тот, который был возвращен. Выглядит хорошо.