具有不可变值的ConcurrentHashMap - 同步替换?

时间:2013-11-08 21:36:16

标签: java immutability concurrenthashmap

我在多线程程序中使用ConcurrentHashMap。该映射将ServerID映射到包含有关服务器的更多信息的对象(无论是否在线,最近使用了多少,等等)。 ServerID和ServerInformation都是不可变的。

要更新服务器信息,我在这个问题中或多或少地提出了建议的B点): What is the preferred way to modify a value in 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);
    };
}

1 个答案:

答案 0 :(得分:2)

是的,替换方法是解决此问题的正确方法。请记住适当地覆盖您的值对象上的equals!

(这假设计算newValue相对便宜并且碰撞相对较少。如果是密集计算并且碰撞很常见,那么引入互斥量并序列化计算可能是值得的。)

最好将作业重新提交给任何正在为您的线程提供服务的队列,或者将其放入延迟队列,而不是实际让工作线程进入休眠状态。睡眠工作者线程总体上很可悲,缺乏可扩展性。