有些编写者通过调用putPrice
方法来更新价格。读取器使用getPrice
获取最新的价格。hasChangedMethod
返回一个布尔值,标识自从上次调用getPrice
以来价格是否发生了变化。
我正在寻找最快的解决方案。我试图实现针对键级别的线程安全一致的读写映射表。
我认为锁定整个映射表可能会导致性能问题,所以我决定在键级别上进行。不幸的是,这并没有像预期的那样工作,并且阻塞了整个映射表。为什么?你能帮我弄清楚我在这里做错了什么吗?
更新:
我想我们可以总结为两个问题:1. 如果某个键正在更新过程中,如何提供对其余键的自由访问。2. 如何确保我的方法具有原子操作,因为它们需要执行多个读/写操作。例如:getPrice()
- 获取价格并更新hasChanged
标志。
PriceHolder.java
public final class PriceHolder {
private ConcurrentMap<String, Price> prices;
public PriceHolder() {
this.prices = new ConcurrentHashMap<>();
//Receive starting prices..
Price EUR = new Price();
EUR.setHasChangedSinceLastRead(true);
EUR.setPrice(new BigDecimal(0));
Price USD = new Price();
USD.setHasChangedSinceLastRead(true);
USD.setPrice(new BigDecimal(0));
this.prices.put("EUR", EUR);
this.prices.put("USD", USD);
}
/** Called when a price ‘p’ is received for an entity ‘e’ */
public void putPrice(
String e,
BigDecimal p) throws InterruptedException {
synchronized (prices.get(e)) {
Price currentPrice = prices.get(e);
if (currentPrice != null && !currentPrice.getPrice().equals(p)) {
currentPrice.setHasChangedSinceLastRead(true);
currentPrice.setPrice(p);
} else {
Price newPrice = new Price();
newPrice.setHasChangedSinceLastRead(true);
newPrice.setPrice(p);
prices.put(e, newPrice);
}
}
}
/** Called to get the latest price for entity ‘e’ */
public BigDecimal getPrice(String e) {
Price currentPrice = prices.get(e);
if(currentPrice != null){
synchronized (prices.get(e)){
currentPrice.setHasChangedSinceLastRead(false);
prices.put(e, currentPrice);
}
return currentPrice.getPrice();
}
return null;
}
/**
* Called to determine if the price for entity ‘e’ has
* changed since the last call to getPrice(e).
*/
public boolean hasPriceChanged(String e) {
synchronized (prices.get(e)){
return prices.get(e) != null ? prices.get(e).isHasChangedSinceLastRead() : false;
}
}
}
Price.java
public class Price {
private BigDecimal price;
public boolean isHasChangedSinceLastRead() {
return hasChangedSinceLastRead;
}
public void setHasChangedSinceLastRead(boolean hasChangedSinceLastRead) {
this.hasChangedSinceLastRead = hasChangedSinceLastRead;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
private boolean hasChangedSinceLastRead = false;
}
Thread.sleep(3000);
调用,因为在这样的关键路径中等待线程没有意义。 - izcegetPrice(...)
方法中,您不需要这行代码prices.put(e, currentPrice);
,因为您已经在currentPrice
变量中引用了相同的Price
对象。 - izcegetPrice()
中的逻辑怎么样?我更新了一个hasChangedSilnceLastRead
属性。例如,如果线程1读取了priceA,线程2修改了priceA,然后线程1再次覆盖了上一次 - 不一致性? - Wild Goat