ConcurrentHashMap с неизменяемыми значениями - синхронизированная замена?

Я использую ConcurrentHashMap в многопоточной программе. Карта сопоставляет идентификаторы ServerID с объектами, содержащими дополнительную информацию о сервере (находится ли он в сети или нет, как часто он использовался в последнее время и т. Д.). И ServerID, и ServerInformation неизменны.

Чтобы обновить информацию о сервере, я делаю более или менее то, что предлагается в пункте B) в этом вопросе: Каков предпочтительный способ изменения значения в ConcurrentHashMap?

а именно (изменено для использования моих собственных имен переменных) это:

public void addUsage(ServerID id, long moreUsage) {
    ServerInfo oldInfo = serverMap.get(id);
    ServerInfo newInfo = oldInfo.addUsage(moreUsage);
    serverMap.put(id, newInfo);
}

Теперь мой вопрос: не следует ли синхронизировать этот метод, чтобы исключить возможность потери обновлений?

Или есть другой способ добиться этого? Может быть, что-то вроде следующего (отредактировано из моей исходной версии, чтобы удалить очевидную ошибку):

public void addUsage(ServerID id, long moreUsage) {
    ServerInfo oldInfo = serverMap.get(id);
    ServerInfo newInfo = oldInfo.addUsage(moreUsage);
    while (!serverMap.replace(id, oldInfo, newInfo) ) {
        oldInfo = serverMap.get(id);
        newInfo = oldInfo.addUsage(moreUsage);
        // try again later
        Thread.sleep(SOME_TIME);
    };
}

person david.mihola    schedule 08.11.2013    source источник
comment
Thread.sleep - неправильный ответ на неудачный replace; вместо этого вы должны повторить вычисление: повторить serverMap.get(id) и повторить addUsage.   -  person Louis Wasserman    schedule 09.11.2013
comment
Вы, конечно, правы! В противном случае замена, вероятно, больше никогда не будет успешной ... Имеет ли смысл изменить мой вопрос, чтобы отразить ваше предложение? Извините, я здесь новенький ...   -  person david.mihola    schedule 09.11.2013


Ответы (1)


Да, метод замены - верный способ решить эту проблему. Просто не забудьте соответствующим образом переопределить равные в ваших объектах значений!

(Это предполагает, что вычисление newValue относительно дешево, а коллизии относительно редки. Если это интенсивное вычисление и коллизии обычны, возможно, стоит ввести мьютекс и сериализовать вычисления.)

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

person Affe    schedule 08.11.2013