最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - Thread Safe money transfer using CAS & No Locks - Stack Overflow

programmeradmin1浏览0评论

I am trying to solve the much talked about problem of transferring money from one account to another in a thread safe manner, given that the accounts exist in memory only.

I was able to easily solve the problem with eventual balance consistency using CAS. However, looking through other solutions on the internet everyone seems to be adamant on using explicit locks to allow for atomicity of transaction but in this case even though transaction operations i.e. withdraw and then deposit are not atomic but are eventually consistent.

I am trying to understand why shall I use a lock? The eventual state is always consistent and there's no possibility of negative balances

This is my simple implementation

  public class Account {
    private final long id;
    private final AtomicReference<BigDecimal> 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(currentBalancepareTo(amount) < 0) {
              throw new InsufficientBalanceException("Unable to withdraw amount: "   + amount +
                    " which is greater than existing balance: " + balance);
        }
        newBalance = currentBalance.subtract(amount);
      } while (!balancepareAndSet(currentBalance, newBalance));
   }

  public void deposit(BigDecimal amount) {
      BigDecimal currentBalance, newBalance;
      do {
          currentBalance = balance.get();
          newBalance = currentBalance.add(amount);
      } while (!balancepareAndSet(currentBalance, newBalance));
  }

  private static class InsufficientBalanceException extends RuntimeException {
      public InsufficientBalanceException(String msg) {
          super(msg);
      }
  }
}

and then for Accounts transfer I have a service class,

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(amountpareTo(BigDecimal.ZERO) < 0) {
          throw new IllegalArgumentException("`amount` must be greater than 0");
      }

      source.withdraw(amount);
      destination.deposit(amount);
      return true;
  }
}

Now, I am trying to understand in what case could the consistency be lost? I believe this is the most high performant we can become.

发布评论

评论列表(0)

  1. 暂无评论