用Java实现银行账户
我是Java线程编程新手。为了理解线程,我试图编写一个简单的程序来模拟银行账户。我只是实现了退出,并尝试对其进行测试。 下面是输出的前几行 T2取款前余额:1000用Java实现银行账户,java,synchronization,Java,Synchronization,我是Java线程编程新手。为了理解线程,我试图编写一个简单的程序来模拟银行账户。我只是实现了退出,并尝试对其进行测试。 下面是输出的前几行 T2取款前余额:1000 T2取款后的余额:990 T1取款前余额:1000 T1取款后余额:980 T2取款前余额:980 T2取款后余额:970 T1取款前余额:970 T1取款后余额:960 我的问题是为什么输出中的第3行(T1取款前的余额:1000)给出的是1000而不是990。如果它是正确的,它应该在第2行。我错过了什么吗。我的方法正确吗? 我的猜
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();
}
}
class银行账户{
私人资产负债表;
公共银行账户(int b){
平衡=b;
}
公共银行账户(){
余额=0;
}
同步的公共int getBalance(){
收益余额;
}
同步公共整数提取(整数w)
{
intb=getBalance();
如果(w可能有一个线程在这些行之间调用draw():
System.out.println("Balance before "+Thread.currentThread().getName()+" withdrawl: "+acc.getBalance());
w = acc.withdraw(amount);
可能的情况:
T2调用getBalance()
T1调用getBalance()
平衡
T2调用撤回()
提款后的余额
平衡
T1调用draw()
提款后的余额
可能有一个线程在这些行之间调用draw():
System.out.println("Balance before "+Thread.currentThread().getName()+" withdrawl: "+acc.getBalance());
w = acc.withdraw(amount);
可能的情况:
T2调用getBalance()
T1调用getBalance()
平衡
T2调用撤回()
提款后的余额
平衡
T1调用draw()
提款后的余额
你没有做任何事情来同步你的run方法,因此撤回之前和之后的PrintLN以及撤回本身都不是原子的。你得到的是线程交错。你没有做任何事情来同步你的run方法,因此撤回之前和之后的PrintLN以及撤回本身都不是原子的。你得到的是thread交错。这是一种可能的线程交错:
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"
这是一种可能的线程交错:
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"
这是一个并发问题
T1检索1000
T1打印“之前”到系统输出1000
T2检索1000
T1进行取款
T1将“之后”打印到系统输出990
T2打印“之前”到系统输出1000
T2退出
T2将“之后”打印到系统输出980
无法按该顺序执行,但您明白了。若要使其正常工作,请使用synchronized block
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());
}
这是一个并发问题
T1检索1000
T1打印“之前”到系统输出1000
T2检索1000
T1进行取款
T1将“之后”打印到系统输出990
T2打印“之前”到系统输出1000
T2退出
T2将“之后”打印到系统输出980
无法按该顺序执行,但您明白了。若要使其正常工作,请使用synchronized block
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());
}
不可能。这就是正在发生的事情。+1不太可能。另一种可能的情况是7.在5之前。现在您已经编辑并添加了一个可能的情况,我将编辑我之前的评论。您最初的回答是“可能有一个线程调用在这些行之间撤回”是我的评论所适用的。啊,好吧。我编辑id之前不知道你的评论出现了。我的错。没有错,帕特里克。仍然是一个很好的答案,我没有撤回我的+1。欢迎来到StackOverflow,顺便说一句。可能没有。这就是正在发生的事情。+1不是真的。另一种可能的情况是7.在5之前。现在你已经编辑并添加了可能的情况是,我会编辑我之前的评论。您最初的回答“可能有一个线程调用在这些行之间撤回”是我的评论所适用的。啊,好吧。我编辑id之前不知道你的评论出现了。我的错。没有错,帕特里克。仍然是一个很好的答案,我没有撤回我的+1。欢迎使用StackOverflow,顺便说一句。你已经同步了帐户(那里的一切都正常),但是如果你希望输出也在“尼斯”中订单,然后你也必须同步它。但一切都是正确的…当T1和T2取款时,帐户是1000。取款后,T1是990(我想更快),T2是980。你已经同步了帐户(那里的一切都正常工作),但如果你想输出的结果也“不错”订单,然后你也必须同步它。但一切都是正确的…当T1和T2取款时,帐户是1000。取款后T1是990(我想更快),T2是980。