我是Java中的线程编程新手。要理解线程,我正在尝试编写一个简单的程序来模拟银行账户。我刚刚实施了撤销并尝试对其进行测试。 输出的前几行是在下面。
T2退出前的余额:1000
T2退出后的余额:990
T1退出前的余额:1000
T1退出后的余额:980
T2退出前的余额:980
T2退出后的余额:970
T1退出前的余额:970
T1退出后的余额:960左
我的问题是为什么输出中的第3行(T1提取前的余额:1000)给出1000而不是990.如果它是正确的,它应该在第2行。我错过了一些东西。我的方法是否正确?
我的猜测是两个线程试图写入控制台并且线程T1只是没有机会在第二行写入。
class BankAccount {
private volatile int balance;
public BankAccount(int b){
balance = b;
}
public BankAccount(){
balance = 0;
}
synchronized public int getBalance(){
return balance;
}
synchronized public int withdraw(int w)
{
int b = getBalance();
if(w <= b){
balance = balance-w;
return w;
}
else
return 0;
}
}
class WithdrawAccount implements Runnable{
private BankAccount acc;
private int amount;
public WithdrawAccount(){
acc = null;
amount = 0;
}
public WithdrawAccount(BankAccount acc,int amount){
this.acc = acc;
this.amount = amount;
}
public void run() {
int w;
for(int i =0; i<20; i++){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Balance before "+Thread.currentThread().getName()+" withdrawl: "+acc.getBalance());
w = acc.withdraw(amount);
System.out.println("Balance after "+Thread.currentThread().getName()+" withdrawl: "+acc.getBalance());
//System.out.println("amount with drawn by: "+Thread.currentThread().getName()+" "+w);
}
}
}
public class TestBankAccount{
public static void main(String[] args) {
BankAccount b = new BankAccount(1000);
WithdrawAccount w = new WithdrawAccount(b,10);
Thread wt1 = new Thread(w);
wt1.setName("T1");
Thread wt2 = new Thread(w);
wt2.setName("T2");
wt1.start();
wt2.start();
}
}
答案 0 :(得分:2)
可能有一个线程在这些行之间调用withdraw():
System.out.println("Balance before "+Thread.currentThread().getName()+" withdrawl: "+acc.getBalance());
w = acc.withdraw(amount);
可能的情况:
答案 1 :(得分:2)
你没有做任何事情来同步你的run方法,所以在撤回之前和之后的printlns和撤回本身都不是原子的。你正在进行线程交错。
答案 2 :(得分:1)
这是可能的线程交错之一:
wt2: calls getBalance() // retrieves 1000
wt2: prints "Balance before T2 withdrawl: 1000"
wt1: calls getBalance() // retrieves 1000 also
wt2: acc.withdraw(amount) // balance is now 990
wt2: prints "Balance after T2 withdrawl: 990"
wt1: acc.withdraw(amount) // balance was 990 after wt1 withdraws. wt1 now withdraws again so balance is 980
wt1: prints "Balance after T2 withdrawl: 980"
答案 3 :(得分:1)
这是一个并发问题
无法按此顺序执行,但您明白了。为了让它像您想要的那样使用synchronized块。
synchronized (acc) {
System.out.println("Balance before " + Thread.currentThread().getName() + " withdrawl: " + acc.getBalance());
w = acc.withdraw(amount);
System.out.println("Balance after " + Thread.currentThread().getName() + " withdrawl: " + acc.getBalance());
}