// this code demonstrates how to organize a cooperation between the threads
// by using the wait() and notifyAll() methods
// this way the balance won't ever be negative

public class AccountDemo5
{
  public static void main(String[] args)
  {
    System.out.println("Deposits\t\tWithdraw\t\tBalance");
    Account5 account = new Account5();
    Thread tD = new DepositThread(account);
    Thread tW = new WithdrawThread(account);

    tD.start();             // start the deposit and withdraw game
    tW.start();
  }
}

class DepositThread extends Thread       // this thread puts 1 on the account
{
  Account5 account;

  DepositThread(Account5 account)
  {
    this.account = account;
  }

  public void run()                      // deposits and withdraw are performed
  {                                      // in regular intervals (1 sec) 
    while (true)                         // but on a random amount (1..10)
    {
      account.deposit((int)(Math.random()*10 + 1));
      try                        // delay it to allow the
      {                          // withdraw thread to proceed
        Thread.sleep(1000); 
      }
      catch(InterruptedException e){}
    }
  }
}

class WithdrawThread extends Thread     // this thread takes 1 from the account
{
  Account5 account;

  WithdrawThread(Account5 account)
  {
    this.account = account;
  }

  public void run()
  {
    while (true)
      account.withdraw((int)(Math.random()*15 + 1));
  }
}

class Account5                          // modufied account class that
{                                       // contains syncronized deposit
  private int balance = 0;              // and withdraw methods
  
  public int getBalance()
  {
    return(balance);
  }

  public synchronized void deposit(int amount)
  {
    balance += amount;
    System.out.println("Deposit " + amount + "\t\t\t\t\t" + getBalance());
    notifyAll();
  }

  public synchronized void withdraw(int amount)
  {
    try
    {
      while (balance < amount)
        wait();
    }
    catch(InterruptedException e){}

    balance -= amount;
    System.out.println("\t\t\tWithdraw " + amount + "\t\t" + getBalance());
  }
}
