我在多线程程序中使用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);
};
}
答案 0 :(得分:2)
是的,替换方法是解决此问题的正确方法。请记住适当地覆盖您的值对象上的equals!
(这假设计算newValue相对便宜并且碰撞相对较少。如果是密集计算并且碰撞很常见,那么引入互斥量并序列化计算可能是值得的。)
最好将作业重新提交给任何正在为您的线程提供服务的队列,或者将其放入延迟队列,而不是实际让工作线程进入休眠状态。睡眠工作者线程总体上很可悲,缺乏可扩展性。