This Java code simulates a banking system with multiple accounts and transactions using threads.
The demo uses Bank, Clerk and Account and Transaction objects to complete the operation. Actually this demo shows how you can use threads to perform the tasks in their own capacity and utilize the maximum system resources. What we do is, we have two clerks and they will do the work separately from each other hence they will work faster using threads. Clerk class implements Runnable interface so that its object will be a thread.
The output of the program includes detailed information about each account, including the original and final balances, the number of credits and debits, and the total credits and debits. This helps verify that the banking operations are performed correctly.
Java Bank Transactions Source Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | import java.util.Random; public class BankOperation { public static void main(String[] args) { int[] initialBalance = { 500, 800 }; // The initial account balances. int[] totalCredits = new int[initialBalance.length]; // Total credits. int[] totalDebits = new int[initialBalance.length]; // Total debits. int[] nCredits = new int[initialBalance.length]; // Number of credits. int[] nDebits = new int[initialBalance.length]; // Number of debits. int transactionCount = 20; // Number of debits and of credits. // Create the bank and the clerks: Bank theBank = new Bank(); // Create a bank. Clerk clerk1 = new Clerk(theBank); // Create the first clerk. Clerk clerk2 = new Clerk(theBank); // Create the second clerk. // Create the accounts, and initialize total credits and debits: Account[] accounts = new Account[initialBalance.length]; for (int i = 0; i < initialBalance.length; i++) { accounts[i] = new Account(i + 1, initialBalance[i]); // Create accounts totalCredits[i] = totalDebits[i] = 0; nCredits[i] = nDebits[i] = 0; } // Create the threads for the clerks as daemon, and start them off: Thread clerk1Thread = new Thread(clerk1); Thread clerk2Thread = new Thread(clerk2); clerk1Thread.setDaemon(true); // Set first as daemon. clerk2Thread.setDaemon(true); // Set second as daemon. clerk1Thread.start(); // Start the first. clerk2Thread.start(); // Start the second. // Generate transactions of each type and pass to the clerks: Random rand = new Random(); // Random number generator Transaction transaction; // Stores a transaction int amount; // stores an amount of money int select; // Selects an account for (int i = 1; i <= transactionCount; i++) { // Generate a credit or debit at random: if (rand.nextInt(2) == 1) { // Generate a random account index for credit operation: select = rand.nextInt(accounts.length); amount = 50 + rand.nextInt(26); // Generate amount of $50 to $75 transaction = new Transaction(accounts[select], // Account Transaction.CREDIT, // Credit transaction amount); // of amount totalCredits[select] += amount; // Keep total credit tally nCredits[select]++; clerk1.doTransaction(transaction); } else { // Generate a random account index for debit operation: select = rand.nextInt(accounts.length); amount = 30 + rand.nextInt(31); // Generate amount of $30 to $60. transaction = new Transaction(accounts[select], // Account. Transaction.DEBIT, // Debit transaction of amount. amount); totalDebits[select] += amount; // Keep total debit tally. nDebits[select]++; clerk2.doTransaction(transaction); } } // Wait until both clerks are done: clerk1.isBusy(); clerk2.isBusy(); // Now output the results: for (int i = 0; i < accounts.length; i++) System.out.println("Account Number:" + accounts[i].getAccountNumber() + "\n" + "Number of credits : " + nCredits[i] + "\n" + "Number of debits : " + nDebits[i] + "\n" + "Original balance : $" + initialBalance[i] + "\n" + "Total credits : $" + totalCredits[i] + "\n" + "Total debits : $" + totalDebits[i] + "\n" + "Final balance : $" + accounts[i].getBalance() + "\n" + "Should be : $" + (initialBalance[i] + totalCredits[i] - totalDebits[i]) + "\n" ); } } //*********************** //Bank.java //*********************** class Bank { // Perform a transaction: public void doTransaction(Transaction transaction) { switch (transaction.getTransactionType()) { case Transaction.CREDIT: synchronized(transaction.getAccount()) { System.out.println("Start credit of " + transaction.getAccount() + " amount: " + transaction.getAmount() ); // Get current balance: int balance = transaction.getAccount().getBalance(); // Credits require require a lot of checks: try { Thread.sleep(10); // wait() time reduced to speed things up. } catch (InterruptedException e) { System.out.println(e); } balance += transaction.getAmount(); // Increment the balance. transaction.getAccount().setBalance(balance); // Restore account balance. break; } case Transaction.DEBIT: synchronized(transaction.getAccount()) { System.out.println("Start debit of " + transaction.getAccount() + " amount: " + transaction.getAmount()); // Get current balance int balance = transaction.getAccount().getBalance(); // Debits require even more checks... try { Thread.sleep(15); // wait()time reduced to speed things up. } catch (InterruptedException e) { System.out.println(e); } balance -= transaction.getAmount(); // Increment the balance. transaction.getAccount().setBalance(balance); // Restore account balance. break; } default: // We should never get here. System.out.println("Invalid transaction"); System.exit(1); } } } //**************************** //Account.java //**************************** // Defines a customer account. public class Account { // Constructor: public Account(int accountNumber, int balance) { this.accountNumber = accountNumber; // Set the account number. this.balance = balance; // Set the initial balance. } // Return the current balance: public int getBalance() { return balance; } // Set the current balance: public void setBalance(int balance) { this.balance = balance; } public int getAccountNumber() { return accountNumber; } public String toString() { return "A//C No. " + accountNumber + " : $" + balance; } private int balance; // The current account balance. private int accountNumber; // Identifies this account. } //*************************** //Clerk.java //*************************** import java.util.*; public class Clerk implements Runnable { Bank theBank; // The in-tray holding transactions: private List inTray = Collections.synchronizedList(new LinkedList()); private int maxTransactions = 8; // Maximum transactions in the in-tray. // Constructor public Clerk(Bank theBank) { this.theBank = theBank; // Who the clerk works for. //inTray = null; //Commented out: don't need this now. } // Receive a transaction: synchronized public void doTransaction(Transaction transaction) { while (inTray.size() >= maxTransactions) try { wait(); } catch (InterruptedException e) { System.out.println(e); } inTray.add(transaction); notifyAll(); } // The working clerk: synchronized public void run() { while (true) { while (inTray.size() == 0) // No transaction waiting? try { wait(); // Then take a break until there is. } catch (InterruptedException e) { System.out.println(e); } theBank.doTransaction((Transaction) inTray.remove(0)); notifyAll(); // Notify other threads locked on this clerk. } } // Busy check: synchronized public void isBusy() { while (inTray.size() != 0) // Is this object busy? try { wait(); // Yes, so wait for notify call. } catch (InterruptedException e) { System.out.println(e); } return; // It is free now. } } //**************************** //Transaction.java //**************************** class Transaction { // Transaction types: public static final int DEBIT = 0; public static final int CREDIT = 1; public static String[] types = { "Debit", "Credit" }; // Constructor: public Transaction(Account account, int transactionType, int amount) { this.account = account; this.transactionType = transactionType; this.amount = amount; } public Account getAccount() { return account; } public int getTransactionType() { return transactionType; } public int getAmount() { return amount; } public String toString() { return types[transactionType] + " A//C: " + ": $" + amount; } private Account account; private int amount; private int transactionType; } |
How this Java Threads Code works?
Here is the break down of the Java code step by step:
BankOperation Class (Main Class):
- It initializes arrays for initial balances, total credits, total debits, number of credits, and number of debits.
- Creates a Bank instance, two Clerk instances, and an array of Account instances.
- Creates two threads for the clerks and starts them.
- Generates random transactions (credits and debits) and passes them to the clerks for processing.
- Waits for both clerks to finish processing transactions.
- Outputs the final results, including account details, number of credits, number of debits, original balance, total credits, total debits, and final balance.
Bank Class:
- This class contains a method
doTransaction
that performs either credit or debit transactions based on the input Transaction object. - Uses synchronization to ensure thread safety when accessing account balances.
Account Class:
- Represents a customer account with an account number, balance, and methods to get and set the balance.
Clerk Class:
- Implements the Runnable interface to work as a separate thread.
- Contains a list (
inTray
) to hold transactions. - Implements methods to receive transactions (
doTransaction
), process transactions (run
), and check if the clerk is busy (isBusy
). - Uses synchronization and waits for proper thread coordination.
Transaction Class:
- This class represents a transaction with an associated account, transaction type (debit or credit), and amount.
- Provides methods to get account details, transaction type, amount, and a string representation.
The wait
and notifyAll
mechanisms ensure proper synchronization between the main thread, clerks, and bank transactions.