Внедрение банковского счета на Java - PullRequest
1 голос
/ 18 мая 2011

Я новичок в программировании потоков на Java.Чтобы понять потоки, я пытаюсь написать простую программу для симуляции банковского счета.Я только что осуществил вывод и пытаюсь проверить его.Первые несколько строк вывода ниже.

Баланс до снятия Т2: 1000Баланс после снятия Т2: 990Баланс до снятия Т1: 1000Баланс после снятия Т1: 980Баланс до снятия Т2: 980Баланс после снятия Т2: 970Баланс до снятия Т1: 970Баланс после снятия Т1: 960

Мой вопрос заключается в том, почему строка 3 (Баланс до снятия Т1: 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();
    }
}

Ответы [ 4 ]

2 голосов
/ 18 мая 2011

Вы ничего не сделали для синхронизации вашего метода запуска, поэтому печати до и после снятия и сам вывод не являются атомарными. Вы получаете чередование потоков.

2 голосов
/ 18 мая 2011

Возможно, один поток вызываетозврат () между этими строками:

System.out.println("Balance before "+Thread.currentThread().getName()+" withdrawl: "+acc.getBalance());
w = acc.withdraw(amount);

Возможный сценарий:

  1. T2 вызывает getBalance ();
  2. T1 вызывает getBalance ();
  3. T2 аутс баланс;
  4. T2 звонки снимать ();
  5. Баланс аутов T2 после снятия;
  6. T1 аутс баланс;
  7. T1 вызовы отозвать ();
  8. Баланс аутов T1 после снятия;
1 голос
/ 18 мая 2011

Это проблема параллелизма

  1. T1 получает 1000
  2. T1 печатает "до" в систему 1000
  3. T2 возвращает 1000
  4. T1выводит
  5. T1 выводит "после" в системный выход 990
  6. T2 выводит "до" выводит в систему 1000
  7. T2 делает вывод
  8. T2выводит "after" на системный выход 980.
  9. ...

Невозможно выполнить точно в таком порядке, но вы поймете, что идея.Чтобы заставить его работать так, как вы хотите, используйте синхронизированный блок.

  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 голос
/ 18 мая 2011

это одно из возможных чередований потоков:

    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"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...