如何从一个帐户到另一个原子帐户赚钱?为了:

public class Account {
    public Account(BigDecimal initialAmount) {...}
    public BigDecimal getAmount() {...}
    public void setAmount(BigDecimal amount) {...}
}

我希望该伪代码:
public boolean transfer(Account from, Account to, BigDecimal amount) {
    BigDecimal fromValue = from.getAmount();
    if (amount.compareTo(fromValue) < 0)
         return false;
    BigDecimal toValue = to.getAmount();
    from.setAmount(fromValue.add(amount.negate()));
    to.setAmount(toValue.add(amount));
    return true;
}

在多线程环境中安全更新帐户,我看到以下危险情况:
acc1 --> acc2  ||  acc2 --> acc1
acc1 --> acc2  ||  acc2 --> acc3  ||  acc3 --> acc1
...

最简单的解决方案是对共享库进行阻塞,但在以下情况下效率低下:
acc1 --> acc2  ||  acc3 --> acc4  and  acc1 != acc3 and acc2 != acc4

我希望独立的 Action 可以并行执行。

UPDATE 似乎建议解决方案:
synchronize (acc1) {
   synchronize (acc2) {
     ....
   }
}

导致死锁,因为依次获得了2个锁...

更新2 您对“在多线程环境中安全更新帐户”的确切含义是什么?唯一担心的是帐户最终将没有负资金,还是还有其他问题?

如果期望acc1(2); acc2(3)acc1 --1--> acc2acc2 --2--> acc1,我希望保持一致:(acc1, acc2)具有(3, 2)值,但没有(4, 2)(3, 4)。总数应为5,而不是1 + 3 = 4或4 + 3 = 7。

您一次要进行多少并发交易? 1000-10000-因此对共享库的锁定效率不高。

最佳答案

一个简单的解决方案是对每个帐户使用锁,但是要避免死锁,您必须始终以相同的顺序获取锁。因此,您可以拥有一个最终的帐户ID,并首先获取一个ID较少的帐户锁:

public void transfer(Account acc1, Account acc2, BigDecimal value) {
    Object lock1 = acc1.ID < acc2.ID ? acc1.LOCK : acc2.LOCK;
    Object lock2 = acc1.ID < acc2.ID ? acc2.LOCK : acc1.LOCK;
    synchronized (lock1) {
       synchronized (lock2) {
          acc1.widrawal(value);
          acc2.send(value);
       }
    }
}

关于java - Java同步: atomically moving money across account pairs?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29280857/

10-10 17:33