假设我要实现一个非常简单的Bank Account
类,并且要注意并发和多线程问题,
即使synchronized
是balance
,也使以下方法AtomicInteger
是一个好主意吗?
另一方面,如果我们将所有方法都同步了,那么就不再使用AtomicInteger
了,对吗?
import java.util.concurrent.atomic.AtomicInteger;
public class Account {
AtomicInteger balance;
public synchronized int checkBalance(){
return this.balance.intValue();
}
public synchronized void deposit(int amount){
balance.getAndAdd(amount);
}
public synchronized boolean enoughFund(int a){
if (balance.intValue() >= a)
return true;
return false;
}
public synchronized boolean transfer_funds(Account acc, int amount){ // dest : acc
if (enoughFund(amount)){
withdraw(amount);
acc.deposit(amount);
return true;
}
return false;
}
public synchronized boolean withdraw(int amount){
if (checkBalance() < amount)
return false;
balance.getAndAdd(-1 * amount);
return true;
}
}
最佳答案
将您的金额声明为AtomicInteger
不会阻止线程在方法执行过程中被抢占(如果未同步)。因此,例如,如果您的方法transfer_funds
没有以任何方式同步,即使您的金额为AtomicInteger
,您也可能会得到意外的结果
public /* synchronized */ boolean transfer_funds(Account acc, int amount){ // dest : acc
if (enoughFund(amount)){
withdraw(amount); // <- thread can be preempted in the middle of method execution
acc.deposit(amount);
return true;
}
return false;
}
这些问题称为比赛条件。一个可能的示例是,当两个线程尝试从同一帐户转移资金时。当一个线程确定存在
enoughFund
来执行信用转帐时,该线程可能会被抢占,同时另一个线程可以从该帐户开始转帐资金。当第一个线程再次开始处理时,它不会再次检查是否有enoughFunds
来执行信用转移(他已经检查过了,但是他的知识可能已经过时了),但是转到下一个执行行。这样,您可能无法获得一致的结果。您可以更改所有帐户开始时的总金额。Cay Horstmann的Core Java书中对此方面有很好的解释-此处免费提供chapter about synchronization。它详细描述了您要问的几乎完全相同的问题。
关于java - 使用AtomicInteger时进行同步,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17253260/