/** @version 1.21 2001-10-26 @author Cay Horstmann */ import java.text.*; /** This program shows data corruption when multiple threads access a data structure. This version shows corruption on Linux. */ public class UnsynchBankTest2 { public static void main(String[] args) { Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE); int i; for (i = 0; i < NACCOUNTS; i++) { TransferThread t = new TransferThread(b, i, INITIAL_BALANCE); t.setPriority(Thread.NORM_PRIORITY + i % 2); t.start(); } } public static final int NACCOUNTS = 10; public static final double INITIAL_BALANCE = 10000; } /** A bank with a number of bank accounts. */ class Bank { /** Constructs the bank. @param n the number of accounts @param initialBalance the initial balance for each account */ public Bank(int n, double initialBalance) { accounts = new double[n]; int i; for (i = 0; i < accounts.length; i++) accounts[i] = initialBalance; ntransacts = 0; } /** Transfers money from one account to another. @param from the account to transfer from @param to the account to transfer to @param amount the amount to transfer */ public void transfer(int from, int to, double amount) { if (accounts[from] < amount) return; accounts[from] -= amount; accounts[to] += amount; ntransacts++; if (ntransacts % NTEST == 0) test(); } /** Prints a test message to check the integrity of this bank object. */ public void test() { double sum = 0; for (int i = 0; i < accounts.length; i++) sum += accounts[i]; System.out.println("Transactions:" + ntransacts + " Sum: " + formatter.format(sum)); } /** Gets the number of accounts in the bank. @return the number of accounts */ public int size() { return accounts.length; } public static final int NTEST = 10000; private double[] accounts; private long ntransacts = 0; private static NumberFormat formatter = NumberFormat.getCurrencyInstance(); } /** A thread that transfers money from an account to other accounts in a bank. */ class TransferThread extends Thread { /** Constructs a transfer thread. @param b the bank between whose account money is transferred @param from the account to transfer money from @param max the maximum amount of money in each transfer */ public TransferThread(Bank b, int from, double max) { bank = b; fromAccount = from; maxAmount = max; } public void run() { try { while (!interrupted()) { for (int i = 1; i <= REPS; i++) { int toAccount = (int)(bank.size() * Math.random()); double amount = maxAmount * Math.random(); bank.transfer(fromAccount, toAccount, amount); } sleep(1); } } catch(InterruptedException e) {} } private Bank bank; private int fromAccount; private double maxAmount; private int REPS = 1000; }