/**
   A bank account has a balance that can be changed by 
   deposits and withdrawals.
*/
public class BankAccount
{
   private double balance;   // shared variable

   /**
      Constructs a bank account with a zero balance
   */
   public BankAccount()
   {
      balance = 0;
   }

   /**
      Deposits money into the bank account.
      @param amount is the amount to deposit
   */
   public synchronized void deposit(double amount)
   {
      System.out.print("Thread " + Thread.currentThread().getName() + " is depositing " + amount);
      double newBalance = balance + amount;
      System.out.println(", new balance is " + newBalance);
      balance = newBalance;
      notifyAll();  // relinquishes the lock on this object and 
                    // notifies all threads that are waiting on this object
   }
   
   /**
      Withdraws money from the bank account.
      @param amount the amount to withdraw
   */
   public synchronized void withdraw(double amount)
      throws InterruptedException
   {
      while (balance < amount)
         wait() ;   //  inside wait() a thread relinquishes the lock on this object 
                    //  and waits until another thread will notify it

      // OK, a thread was notified, it was awakened from waiting, 
      // and now it can proceed to execute the remaining section of code

      System.out.print("Thread " + Thread.currentThread().getName() + " is withdrawing " + amount);
      double newBalance = balance - amount;
      System.out.println(", new balance is " + newBalance);
      balance = newBalance;
   }
   
   /**
      Gets the current balance of the bank account.
      @return the current balance
   */
   public double getBalance()
   {      return balance;   }
   
}