我有一个类似this question中的示例。
我确保保留获得锁的顺序
public class Account {
private int balance;
public void withdraw(int value) {
balance -= value;
}
public void deposit(int value) {
balance += value;
}
}
public class Bank {
private List<Account> accounts;
private int slots;
public Bank(int slots) {
accounts = new ArrayList<Account>(Collections.nCopies(slots, new Account()));
this.slots = slots;
}
public void transfer(int fromId, int toId, int value) {
synchronized(accounts.get(Math.min(fromId, toId))) {
synchronized(accounts.get(Math.max(fromId, toId))) {
accounts.get(fromId).withdraw(value);
accounts.get(toId).deposit(value);
}
}
}
我的理解是,如果一个线程执行从账户A到B的转移,而另一个线程想要从B转移到A,那么它必须等待锁定(如果我错了,请纠正我)。 / p>
确保只有一个线程可以从A传输到B,但另一个线程可以从B传输到A的最佳方法是什么?
我在考虑为每个Account对象声明两组锁:
public class Account{
public Object fromLock = new Object();
public Object toLock = new Object();
// ...
}
根据转账是否来自特定账户,获取其中一个。这是正确的方式吗?
编辑:问题是:假设提款和存款方式需要一些时间才能完成。如何允许2个用户(与不同线程相关联)同时进行相互转移而无需等待?
答案 0 :(得分:1)
您实施帐户的方式,您绝不希望多个交易在任何特定时间影响单个帐户。具体来说,因为&#39;平衡&#39;是一个int,并且&#39;撤回&#39;和&#39;存款&#39;只是改变了“平衡”的价值。直接地,使用非原子操作,你永远不会想要调用&#39;撤回&#39;和&#39;存款&#39;交错。
另一方面,如果你要表示平衡&#39;作为AtomicInteger,然后调用“撤消”#39;和&#39;存款&#39;可以安全地交错。但是,如果您同时使用了“来自”并且只有一个帐户可以同时将钱转入任何给定的帐户。例如。假设账户B和C都希望将资金转入账户A - 使用“锁定”,这两个转账必须被序列化。
稍微退一步,为什么有必要阻止并发存款进入给定帐户(假设帐户的余额以线程安全的方式变异)?当然,有必要确保任何给定的帐户最多只能涉及一个交易,因为&#39;来自&#39;在任何给定时间的帐户;但是我不明白为什么这些约束必须存在于&#39; to&#39;帐户(再次,假设&#39;余额&#39;以线程安全的方式操作)。
所以,除非我在这里遗漏了一些东西,否则我认为代表&#39;平衡&#39;作为一个AtomicInteger,只抓住&#39;来自&#39;帐户里面的转移&#39;应该满足你的要求。
注意:在我被遗忘之前,请允许我说我的评论仅适用于您的示例代码中表示银行帐户的具体方式(即在执行这些类型的生产系统中,有充分的理由确保在交易中执行配对存款和取款。