如何从一个帐户到另一个原子帐户赚钱?为了:
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--> acc2
和acc2 --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/