Listing 1

/**
 * Description: a driver program. Creates a thread to run simple double-entry bookkeeping 
 *              processor.
 */ 

public class LockingRun { 

    private static double[] accounts;
    
    public static void main(String[] args) {
        
        // Create some accounts between which funds will be moved.
        accounts = new double[] {109.0, 242.00, 455.89, 231.92, 1200.01};
        
        Thread processor = new TransactionProcessor(accounts);  
        processor.start();

    }
    
}




Listing 2

import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.*;

/**
 * Description: a simple double-entry book-keeping processor. When amounts are transferred between accounts,
 *              a transaction lock ensures that the transfer (debit one account, credit another) happens
 *              atomically.
 */

 class TransactionProcessor extends Thread {
     
     private Lock transactionLock = new ReentrantLock();
     private Condition enoughMoney = transactionLock.newCondition();
     private double [] accounts;
     private volatile boolean stopped = false;
     
     Random random = new Random();
     
   /**
    *   Constructs the transaction processor.
    */
    public TransactionProcessor(double[] accounts) {
       
       this.accounts = accounts;
       
    }

   /**
    *   Transfers money from one account to another.
    */
    private void transfer(double[] accounts, int fromAccount, int toAccount, double amount) {
        
       transactionLock.lock();
       
       try {
           
          //  If there isn't enough money in the from-account, wait and see if a deposit is eventually made.
          while (accounts[fromAccount] < amount)
              
             enoughMoney.await(1000, TimeUnit.MILLISECONDS);
                 
          System.out.printf("Completing transfer of $%.2f from account %d to account %s %n",
                              amount, fromAccount, toAccount);
          accounts[fromAccount] -= amount;
          accounts[toAccount] += amount;

          printAccountPortfolio(accounts);
          
          //  Maybe there's enough money now. Wake up all threads waiting on this condition.
          enoughMoney.signalAll();
          
       } catch (InterruptedException ie) {
          
           return;
           
       } finally {
           
          transactionLock.unlock();
          
       }
       
    }
 
   /**
    *   Print a list of all acounts and their balances.
    */
    private void printAccountPortfolio(double[] accounts) {
                        
       transactionLock.lock();
       double total = 0.0;
       try {
           
           for (int index = 0; index < 5; index++) {
               
               System.out.printf("\tAccount: %d $%.2f %n", index, accounts[index]);
               total = total + accounts[index];
               
           }
           
           //  If the transfers between accounts are happening atomically, this total won't change.
           System.out.printf("\tTotal balances: $%.2f %n", total);
          
       } finally {
           
           transactionLock.unlock();
       }
       
    }
    
    public void run() {
        
        try {
            
           while (!stopped) {
               
              // Choose a pair of to- and from-accounts at random.
              int toAccount = random.nextInt(5);
              int fromAccount = random.nextInt(5);

              //  Ignore transfers to and from the same account.
              if (toAccount != fromAccount) {
                  
                  //  Create a random amount under $25 to transfer.
                  double amount = 25 * random.nextDouble();           
                  
                  System.out.printf("Attempting to transfer $%.2f from account %d to account %d %n", 
                                      amount, fromAccount, toAccount);
                  transfer(accounts, fromAccount, toAccount, amount);
              
              }
              
              Thread.sleep(random.nextInt(100));
              
           }
           
        } catch (InterruptedException ie) {
            
            return;
            
        }
        
     }
    
 }