BankingThread.java - Synchronization Sample Program

This section provides a tutorial example on how to solve the banking synchronization issue with Java synchronized methods.

Now, let's write a Java program to see how the synchronization technique can solve the bank problem. Two classes are designed to simulate a bank system:

BankingThread class:

/* BankingThread.java
 - Copyright (c) 2014, HerongYang.com, All Rights Reserved.
 */
import java.util.*;
public class BankingThread extends Thread {
   private long[] t_balance; // acount balance
   private long t_count; // number of transactions done so far
   public BankingThread(ThreadGroup g, String n) {
      super(g,n);
      t_count = 0;
      int m = BankingMain.accountCount();
      t_balance = new long[m];
      for (int i=0; i<m; i++) t_balance[i] = 0;
   }
   public long transactionCount() {
      return t_count;
   }
   public long getBalance(int i) {
      return t_balance[i];
   }
   public void run() {
      while (!isInterrupted()) {
         t_count++; 
         Random r = BankingMain.getRandom();
         long t_step = BankingMain.getStep();
         int m = BankingMain.accountCount();
         int n = r.nextInt(m); // account number
         int t = 2*r.nextInt(2)-1; // type of transaction
         long a = (long) t*r.nextInt(10000); // amount of transaction
         if (t_step==1) 
            if (BankingMain.doTransaction1(n,a)) t_balance[n] += a;
         if (t_step==2)
            if (BankingMain.doTransaction2(n,a)) t_balance[n] += a;
         if (t_step==3)
            if (BankingMain.doTransaction3(n,a)) t_balance[n] += a;
         if (t_step==4)
            if (BankingMain.doTransaction4(n,a)) t_balance[n] += a;
         try {
            sleep(10); // wait for the next customer
         } catch (InterruptedException e) {
            break;
         }
      }
   }
}

BankingMain class:

/* BankingMain.java
 - Copyright (c) 2014, HerongYang.com, All Rights Reserved.
 */
import java.util.*;
public class BankingMain {
   public static final int a_maxi = 10; // number of accounts
   public static long[] balance = new long[a_maxi];
   public static Random r_number;
   private static final int t_maxi = 5; // number of threads
   private static BankingThread[] t_list = new BankingThread[t_maxi];
   private static long t_step;
   private static Object o_lock;
   private static Object[] a_lock = new Object[a_maxi];
   public static void main(String[] a) {
      o_lock = new Object();
      for (int i=0; i<a_maxi; i++) a_lock[i] = new Object();
      t_step = 1; // using doTransaction1();
      System.out.println("No synchronization:");
      testATM();
      printResult();
      t_step = 2; // using doTransaction2();
      System.out.println("Synchronized method:");
      testATM();
      printResult();
      t_step = 3; // using doTransaction3();
      System.out.println("Synchronized statements:");
      testATM();
      printResult();
      t_step = 4; // using doTransaction4();
      System.out.println("Synchronized statements per account:");
      testATM();
      printResult();
   }
   private static void testATM() {
      for (int i=0; i<a_maxi; i++) balance[i] = 0;
      r_number = new Random();
      ThreadGroup g = new ThreadGroup("ATM");
      for (int i=0; i<t_maxi; i++) {
         BankingThread t = new BankingThread(g,String.valueOf(i));
         t.start();
         t_list[i] = t;
      }
      try {
         Thread.sleep(5*1000); // working period
      } catch (InterruptedException e) {
         System.out.println("Interrupted in the mainthread.");
      }
      g.interrupt();
      while (g.activeCount()>0); // wait for all threads to end
   }
   private static void printResult() {
      System.out.print("Account");
      for (int i=0; i<t_maxi; i++)
         System.out.print(", ATM "+i);
      System.out.print(", Transaction Sum, Balance");
      for (int j=0; j<a_maxi; j++) {
         System.out.print("\n"+j);
         long sum = 0;
         for (int i=0; i<t_maxi; i++) {
            sum += t_list[i].getBalance(j);
            System.out.print(", "
               +getCurrency(t_list[i].getBalance(j)));
         }
         System.out.print(", "+getCurrency(sum)+
            ", "+getCurrency(balance[j]));
      }
      System.out.print("\n# of Transactions");
      for (int i=0; i<t_maxi; i++)
         System.out.print(", "+t_list[i].transactionCount());
      System.out.print("\n");
   }
   private static String getCurrency(long d) {
      long i = d/100;
      long f = Math.abs(d)%100;
      String fs = String.valueOf(f);
      if (f<10) fs = "0"+fs;
      return String.valueOf(i)+"."+fs;
   }
   public static long getStep() {
      return t_step;
   }
   public static int accountCount() {
      return a_maxi;
   }
   public static Random getRandom() {
      return r_number;
   }
   public static long getBalance(int i) {
      return balance[i];
   }
   public static boolean doTransaction1(int i, long a) {
      boolean ok = false;
      long c = balance[i]; // get current balance
      ok = c+a>0;
      if (ok) { // stop accout balance going negative
         try {
            Thread.sleep(1); // slow down the process
         } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // re-set the flag
         }
         balance[i] = c+a; // set current balance
      }
      return ok;
   }
   public synchronized static boolean doTransaction2(int i, long a) {
      boolean ok = false;
      long c = balance[i]; // get current balance
      ok = c+a>0;
      if (ok) { // stop accout balance going negative
         try {
            Thread.sleep(1); // slow down the process
         } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // re-set the flag
         }
         balance[i] = c+a; // set current balance
      }
      return ok;
   }
   public static boolean doTransaction3(int i, long a) {
      boolean ok = false;
      synchronized (o_lock) {
         long c = balance[i]; // get current balance
         ok = c+a>0;
         if (ok) { // stop accout balance going negative
            try {
               Thread.sleep(1); // slow down the process
            } catch (InterruptedException e) {
               Thread.currentThread().interrupt(); // re-set the flag
            }
            balance[i] = c+a; // set current balance
         }
      }
      return ok;
   }
   public static boolean doTransaction4(int i, long a) {
      boolean ok = false;
      synchronized (a_lock[i]) {
         long c = balance[i]; // get current balance
         ok = c+a>0;
         if (ok) { // stop accout balance going negative
            try {
               Thread.sleep(1); // slow down the process
            } catch (InterruptedException e) {
               Thread.currentThread().interrupt(); // re-set the flag
            }
            balance[i] = c+a; // set current balance
         }
      }
      return ok;
   }
}

Couple of notes about this program:

See the next section for the execution output.

Last update: 2014.

Table of Contents

 About This Book

 Installing JDK 1.8 on Windows

 Execution Process, Entry Point, Input and Output

 Primitive Data Types and Literals

 Bits, Bytes, Bitwise and Shift Operations

 Managing Bit Strings in Byte Arrays

 Reference Data Types and Variables

 StringBuffer - The String Buffer Class

 System Properties and Runtime Object Methods

 Generic Classes and Parameterized Types

 Generic Methods and Type Inference

 Lambda Expressions and Method References

 Execution Threads and Multi-Threading Java Programs

 ThreadGroup Class and "system" ThreadGroup Tree

Synchronization Technique and Synchronized Code Blocks

 Why Synchronization Is Needed in Multi-Threading Applications?

 Synchronization Technique - Lock and Synchronized Code

 "synchronized" - How Java Supports Synchronization

BankingThread.java - Synchronization Sample Program

 BankingThread.java - Synchronization Sample Program Output

 Deadlock Condition Example Programs

 Garbage Collection and the gc() Method

 Outdated Tutorials

 References

 PDF Printing Version