// BankDemo2.java // by Mark Weiss, Fall 2002 // Uses multiple monitors and obtains them in a uniform order. // This prevents deadlock. // Each Account has a unique ID number. class Account { public void deposit( int d ) { synchronized( CRITICAL_SECTION_1 ) { balance += d; CRITICAL_SECTION_1.notifyAll( ); } } public void withdraw( int d ) { synchronized( CRITICAL_SECTION_1 ) { 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( ); } class Bank { public Bank( int numAccounts ) { accts = new Account[ numAccounts ]; for( int i = 0; i < accts.length; i++ ) accts[ i ] = new Account( ); } // not deadlock prone: obtain monitors in same order. // (first, the lowest account number, then the higher account number) public static void transfer( Account to, Account from, int d ) { Account low = to; Account high = from; if( to.getID( ) > from.getID( ) ) { Account tmp = low; low = high; high = tmp; } synchronized( low ) { try // slow things down; CPU is too fast { Thread.sleep( 1 ); } catch( InterruptedException e ) { } synchronized( high ) { 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( ); for( int i = 0; i < 100; i++ ) { theBank.transfer( theBank.getAccount( (int) ( Math.random( ) * size ) ), theBank.getAccount( (int) ( Math.random( ) * size ) ), 1 ); } } private Bank theBank; } class BankDemo2 { public static void main( String [] args ) { Thread threads[] = new Thread[ 10 ]; Bank bank = new Bank( 4 ); for( int i = 0; i < threads.length; i++ ) { threads[ i ] = new TapeThread( bank ); threads[ i ].setPriority( 1 + i % 10 ); threads[ i ].start( ); } for( int i = 0; i < threads.length; i++ ) { try { threads[ i ].join( ); } catch( InterruptedException e ) { System.out.println( "Interrupted " + i ); } System.out.println( "Finished " + i ); } } }