一种方法是写时复制方案,如下所示:
public class Prices {
private volatile Map<String, Integer> prices = Collections.emptyMap();
public void putPrice(String ticker, int price) {
HashMap<String, Integer> newPrices = new HashMap<String, Integer>(prices);
newPrices.put(ticker, price);
prices = newPrices;
}
public Integer getPrice(String ticker) {
return prices.get(ticker);
}
}
这对获取具有最小的开销 - 从 volatile 读取,然后是正常的哈希查找。但是,它对 puts 有很大的开销——创建一个全新的映射,以及对 volatile 的写入。如果您的读写比率很高,这可能仍然是一个很好的权衡。
您可以通过仅在实际需要添加新条目而不是更新现有条目时更改地图来改进这一点;您可以通过使用可变值来实现:
public class Prices {
private volatile Map<String, AtomicInteger> prices = Collections.emptyMap();
public void putPrice(String ticker, int price) {
AtomicInteger priceHolder = prices.get(ticker);
if (priceHolder != null) {
priceHolder.set(price);
}
else {
HashMap<String, AtomicInteger> newPrices = new HashMap<String, AtomicInteger>(prices);
newPrices.put(ticker, new AtomicInteger(price));
prices = newPrices;
}
}
public Integer getPrice(String ticker) {
AtomicInteger priceHolder = prices.get(ticker);
if (priceHolder != null) return priceHolder.get();
else return null;
}
}
我不确定 an 的性能特征是什么AtomicInteger
;这可能比看起来要慢。假设AtomicInteger
不是不合理的慢,这应该非常快 - 它涉及从 volatile 读取两次加上每次获取的正常哈希查找,从 volatile 读取,哈希查找,以及对 volatile 的一次写入以更新现有价格。它仍然涉及复制地图以添加新价格。然而,在典型的市场中,这种情况并不经常发生。