Подтвердить что ты не робот

ConcurrentHashMap put vs putIfAbsent

Java Docs говорит, что putIfAbsent эквивалентно

   if (!map.containsKey(key)) 
      return map.put(key, value);
   else
      return map.get(key);

Итак, если ключ существует на карте, он не обновляет его значение. Правильно ли это?

Что делать, если я хочу обновить значение ключа на основе некоторых критериев? Скажите время истечения срока действия и т.д.

Будет ли это лучше использовать для добавления и обновления кеша?

public void AddToCache(T key, V value)
{
   V local = _cache.putifabsent(key, value);

   if(local.equals(value) && local.IsExpired() == false){
     return;
   }
   // this is for updating the cache with a new value
   _cache.put(key, value);
}
4b9b3361

Ответ 1

Таким образом, он не обновляет значение ключа. это правильно?

Это правильно. Он вернет текущее значение, которое уже было на карте.

будет ли это лучше для добавления и обновления кеша?

Несколько вещей улучшат вашу реализацию.

1. Вы не должны использовать putIfAbsent для проверки, существует ли он, вы должны использовать его только тогда, когда хотите убедиться, что он не существует, а затем putIfAbsent. Вместо этого вы должны использовать map.get для проверки его существования (или map.contains).

    V local = _cache.get(key);
    if (local.equals(value) && !local.IsExpired()) {
        return;
    }

2. Вместо того, чтобы поставить вас на замену, это связано с тем, что условие гонки может происходить там, где if может быть оценено как ложное двумя или более потоками, в которых один из двух (или более) потоков будут перезаписывать другие потоки.

Вместо этого вы можете replace

Когда все сказано и сделано, это может выглядеть так:

public void AddToCache(T key, V value) {
    for (;;) {

        V local = _cache.get(key);
        if(local == null){
            local = _cache.putIfAbsent(key, value);
            if(local == null)
                return;
        }
        if (local.equals(value) && !local.IsExpired()) {
            return;
        }

        if (_cache.replace(key, local, value))
            return;
    }
}

Ответ 2

Ваш код будет вызывать NPE, если ключ ранее не был на карте.

Кроме этого, хотя это разумная идея, он не будет работать в "параллельной" среде. Причина, по которой был добавлен метод putIfAbsent(), состояла в том, чтобы карта могла управлять атомарностью операции с использованием любой базовой поддержки, которую она использует, чтобы сделать операции потокобезопасными. В вашей реализации два разных вызывающих абонента могут завершить шаг друг на друга (первый заменяет истекшее значение новым, а второй сразу заменяет первый новый вторым).