Я пытаюсь решить много обсуждаемой проблемы передачи денег с одной учетной записи в другую безопасным образом, учитывая, что учетные записи существуют только в памяти. Тем не менее, просмотр других решений в Интернете, все, кажется, непреклонны для использования явных замков, чтобы обеспечить атомность транзакции, но в этом случае даже несмотря на то, что операции транзакций, то есть снятие, а затем депозит не являются атомными, но в конечном итоге согласованы. < /P>
Я пытаюсь понять, почему я буду использовать замк? Возможное состояние всегда согласованно, и нет возможности негативных балансов < /p>
Это моя простая реализация < /p>
public class Account {
private final long id;
private final AtomicReference balance;
public Account(long id, BigDecimal balance) {
this.id = id;
this.balance = new AtomicReference(balance);
}
public long getId() {
return id;
}
public void withdraw(BigDecimal amount) {
BigDecimal currentBalance, newBalance;
do {
currentBalance = balance.get();
if(currentBalance.compareTo(amount) < 0) {
throw new InsufficientBalanceException("Unable to withdraw amount: " + amount +
" which is greater than existing balance: " + balance);
}
newBalance = currentBalance.subtract(amount);
} while (!balance.compareAndSet(currentBalance, newBalance));
}
public void deposit(BigDecimal amount) {
BigDecimal currentBalance, newBalance;
do {
currentBalance = balance.get();
newBalance = currentBalance.add(amount);
} while (!balance.compareAndSet(currentBalance, newBalance));
}
private static class InsufficientBalanceException extends RuntimeException {
public InsufficientBalanceException(String msg) {
super(msg);
}
}
}
< /code>
, а затем для передачи учетных записей у меня есть класс услуг, < /p>
public class AccountServiceAllowVariance {
public boolean transfer(Account source, Account destination, BigDecimal amount) {
Objects.requireNonNull(source, "``from` account cannot be null");
Objects.requireNonNull(destination, "`to` account cannot be null");
Objects.requireNonNull(amount, "`amount` cannot be null");
if(source.equals(destination)) {
throw new IllegalArgumentException("`from` & `to` accounts cannot be same");
}
if(amount.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("`amount` must be greater than 0");
}
source.withdraw(amount);
source.deposit(amount);
return true;
}
}
< /code>
Теперь я пытаюсь понять, в каком случае может быть потеряна последовательность? Я считаю, что это самый высокий результат, которым мы можем стать.
Подробнее здесь: https://stackoverflow.com/questions/795 ... s-no-locks
Безопасная перевода потока с использованием CAS и без замков ⇐ JAVA
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение