// BankDemo1.java // by Mark Weiss, Fall 2002 // revised by Kip Irvine, 9/11/03 // Uses multiple monitors, but account transfers can cause a deadlock class Account { public void deposit( int d ) { System.out.println("Entering deposit for account #" + ID); synchronized( CRITICAL_SECTION_1 ) { System.out.println("Entering deposit's critical section"); balance += d; CRITICAL_SECTION_1.notifyAll( ); } } public void withdraw( int d ) { System.out.println("Entering withdraw for account #" + ID); synchronized( CRITICAL_SECTION_1 ) { System.out.println("Entering withdraw's critical section"); while ( balance < d ) { try { CRITICAL_SECTION_1.wait( ); } catch( InterruptedException e ) { } } balance -= d; } } public int getID( ) { return ID; } private final int ID = count++; // new private static int count = 0; // new private int balance = 10000; // start with $10,000 private Object CRITICAL_SECTION_1 = new Object( ); private int mAcctNum; } class Bank { public Bank( int numAccounts ) { accts = new Account[ numAccounts ]; for( int i = 0; i < accts.length; i++ ) accts[ i ] = new Account( ); } // This method is deadlock prone! public static void transfer( Account to, Account from, int d ) { if( to == from ) return; System.out.println("About to transfer funds from account " + from.getID() + " to " + to.getID() ); synchronized( from ) { System.out.println("...locking acct #" + from.getID( ) ); try // slow things down; CPU is too fast { Thread.sleep( 1 ); } catch( InterruptedException e ) { } synchronized( to ) { System.out.println("...locking acct #" + to.getID( ) ); System.out.println("...transferring " + d + " dollars from account " + from.getID( ) + " to " + to.getID( ) ); from.withdraw( d ); to.deposit( d ); } } } public int size( ) { return accts.length; } public Account getAccount( int num ) { return accts[ num ]; } private final Account [] accts; } class TapeThread extends Thread { public TapeThread( Bank b ) { theBank = b; } public void run( ) { int size = theBank.size( ); // randomly choose different back accounts as the source and target // of money transfers. for( int i = 0; i < 50; i++ ) { theBank.transfer( theBank.getAccount( (int) ( Math.random( ) * size ) ), theBank.getAccount( (int) ( Math.random( ) * size ) ), 1 ); } } private Bank theBank; } class BankDemo1 { public static void main( String [] args ) { Thread threads[] = new Thread[ 10 ]; int numberOfAccounts = 4; Bank bank = new Bank( numberOfAccounts ); for( int i = 0; i < threads.length; i++ ) { threads[ i ] = new TapeThread( bank ); threads[ i ].setPriority( 1 + i % 10 ); // 1,2,3,4,5,6,7,8,9,10 threads[ i ].start( ); } for( int i = 0; i < threads.length; i++ ) { try { threads[ i ].join( ); // main will wait for all threads } catch( InterruptedException e ) { System.out.println( "Interrupted " + i ); } System.out.println( "Thread " + i + " is Finished" ); } } }