Есть писатель, который обновляет цены, вызывая метод putPrice
. Читатель использует getPrice
для получения последней цены. hasChangedMethod
возвращает логическую идентификацию, если цена была изменена с момента последнего вызова getPrice
.
Я ищу быстрое решение. Я пытаюсь достичь потокобезопасного последовательного чтения/записи на карте на ключевом уровне.
Я думаю, что блокировка всей карты может вызвать проблему с производительностью, поэтому я решил сделать ее на ключевом уровне. К сожалению, он не работает должным образом и блокирует всю карту. Зачем? Не могли бы вы помочь мне выяснить, что я здесь делаю неправильно?
UPDATE:
Я думаю, мы можем обобщить два вопроса: 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;
}