Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用Java实现银行账户_Java_Synchronization - Fatal编程技术网

用Java实现银行账户

用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行。我错过了什么吗。我的方法正确吗? 我的猜

我是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();
    }
}
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。