 
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;
        }
    }    
       
    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( );
    }
    
    // This method is deadlock prone!
    public static void transfer( Account to, Account from, int d )
    {
        if( to == from )
            return;
            
        synchronized( from )
        {
            try // slow things down; CPU is too fast 
            {
                Thread.sleep( 1 );
            }
            catch( InterruptedException e )
            {
            }
            synchronized( to )
            {
                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 < 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 ];
        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 );
        }
        
    }
}
        
