【发布时间】:2015-02-05 17:04:53
【问题描述】:
我有一个类似于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的转账,那么它必须等待锁(如果我错了,请纠正我)。
确保只有一个线程可以从 A 传输到 B,而另一个线程可以从 B 传输到 A 的最佳方法是什么?
我正在考虑为每个 Account 对象声明两组锁:
public class Account{
public Object fromLock = new Object();
public Object toLock = new Object();
// ...
}
并获得其中一个,具体取决于转账是来自给定账户还是来自给定账户。这是正确的做法吗?
编辑:问题是:假设提款和存款方法需要一些时间才能完成。您如何允许 2 个用户(与不同的线程相关联)在不等待的情况下同时相互传输?
【问题讨论】:
-
快速评论,你设置的构造函数
mBalance = 0在java中是没有必要的。您可以阅读docs.oracle.com/javase/tutorial/java/nutsandbolts/… 了解更多信息。此外,用“m”en.wikipedia.org/wiki/Naming_convention_(programming)#Java 命名变量并不常见 -
这没有多大意义:如果一个线程退出而另一个线程存款,您的帐户将不再是线程安全的。状态 mBalance 必须由单个锁保护。
-
@JBNizet,为什么没有意义?不然你怎么让我给你转钱,而你同时给我转钱?
-
如果你允许,那么一个线程会尝试减少 mBalance,而另一个线程会尝试增加它。这两个操作必须是互斥的,否则你可能会得到一个错误的 mBalance。这正是您需要同步的原因。
-
@Emz,我最初重用了链接问题中的代码。现在修好了。
标签: java multithreading locking synchronized