2

我在多线程程序中使用 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);
    };
}
4

1 回答 1

2

是的,替换方法是解决这个问题的正确方法。只要记住在你的值对象上适当地覆盖等于!

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

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

于 2013-11-08T21:45:27.227 回答