我们在银行中有一百个帐户,有两个作为线程实现的职员,他们使用同步方法transferMoney将每1000次钱从编号为accountNumberFrom的帐户转移到帐户accountNumberTo。由于所有帐户均以余额0开头,并且从一个帐户取回的资金转移到另一个帐户,因此在所有交易之后余额应为零。大多数时候都是这样,但并非总是如此。尽管很少发生,但有时交易后的余额不等于0。怎么了?
public class Clerk extends Thread {
private Bank bank;
public Clerk(String name, Bank bank) {
super(name);
this.bank=bank;
start();
}
public void run() {
for (long i=0; i<1000; i++) {
int accountNumberFrom = (int) (Math.random()*100);
int accountNumberTo = (int) (Math.random()*100);
float amount = (int) (Math.random()*1000) - 500;
bank.transferMoney(accountNumberFrom, amount);
bank.transferMoney(accountNumberTo, -amount);
}
}
}
and a class Bank
public class Bank {
Account[] account;
public Bank() {
account = new Account[100];
for (int i=0; i < account.length; i++)
account[i] = new Account();
}
public synchronized void transferMoney(int accountNumber, float amount) {
float oldBalance = account[accountNumber].getBalance();
float newBalance = oldBalance + amount;
account[accountNumber].setBalance(newBalance);
}
}
public class Banking {
public static void main (String[] args) {
Bank myBank = new Bank();
/**
* balance before transactions
*/
float sum=0;
for (int i=0; i<100; i++)
sum+=myBank.account[i].getBalance();
System.out.println("before: " + sum);
new Clerk ("Tom", myBank);
new Clerk ("Dick", myBank);
/**
* balance after transactions
*/
for (int i=0; i<100; i++)
sum+=myBank.account[i].getBalance();
System.out.println("after: " + sum);
}
}
一个问题是,同步的transferMoney
方法仅使用一个帐户,因此另一个线程可能会访问帐户余额之后
在您的示例中,synchronized
仅阻止对myBank.transferMoney
的所有线程调用,但不能确保在main thread
上完成的所有线程,您可以像这样更新源代码:
非常感谢您的有用答案。我修改了代码,现在它可以正常工作: