【发布时间】:2019-04-06 14:52:54
【问题描述】:
我正在实施一个并行银行系统,所有操作都可以同时运行。我已经实现了一个线程安全的transferMoney 方法,它将amount 从帐户from 转移到to。
transferMoney 使用以下代码实现:
public boolean transferMoney(Account from, Account to, int amount) {
if (from.getId() == to.getId()){
return false;
}else if(from.getId() < to.getId()) {
synchronized(to) {
synchronized(from) {
if(from.getBalance() >= amount) {
from.setBalance(from.getBalance()-amount);
to.setBalance(to.getBalance()+amount);
}else {
return false;
}
}
}
}else {
synchronized(from) {
synchronized(to) {
if(from.getBalance() >= amount) {
from.setBalance(from.getBalance()-amount);
to.setBalance(to.getBalance()+amount);
}else {
return false;
}
}
}
}
return true;
}
为了防止死锁,我已指定始终以相同的顺序获取锁。为了确保以相同的顺序获取锁,我使用了 Account 的唯一 ID。
另外,我实现了一个方法,用下面的代码总结银行里的总金额:
public int sumAccounts(List<Account> accounts) {
AtomicInteger sum = new AtomicInteger();
synchronized(Account.class) {
for (Account a : accounts) {
sum.getAndAdd(a.getBalance());
}
}
return sum.intValue();
}
问题
当我同时运行sumAccounts() 和transferMoney() 时,即使没有添加任何钱,我也会在银行之前更多(有时更少)钱。据我了解,如果我通过synchronized(Account.class) 锁定所有Account 对象,我是否应该在阻止transferMoney() 的执行时获得正确的银行金额?
到目前为止我已经尝试过什么
我尝试了以下方法:
- 像上面一样同步
Account.class(不起作用) - 在
for each循环中同步特定帐户(当然这不是线程安全的,因为事务是同时发生的) - 通过
ReentrantLock对象同步这两种方法。这行得通,但对性能有很大影响(需要的时间是顺序代码的三倍) - 在类级别同步这两种方法。这也有效,但再次比按顺序运行操作花费的时间长三倍。
Account.class 上的锁定不应该阻止任何进一步的transferMoney() 处决吗?如果没有,我该如何解决这个问题?
编辑:
getBalance()的代码:
public int getBalance() {
return balance;
}
【问题讨论】:
-
在 Account.class 上同步不会获取任何 Account 实例上的监视器;另见stackoverflow.com/questions/2056243/…
-
Account.getBalance()是同步方法吗?如果没有,您将得到之前的余额,如果减去一个帐户并加上新添加的帐户的余额 -
@Cratylus 不,它不同步,因为我在
transferMoney()中访问它们时锁定了对象。我添加了它以进行测试,但它仍然给了我错误的结果。 -
@pr0f3ss:你能把
getBalance()的代码贴出来吗? -
@Cratylus 刚刚将其添加为问题的编辑
标签: java multithreading thread-safety synchronized reentrantlock