C'è un oggetto ponte che è condiviso tra 10 thread auto. Il ponte è ad una corsia sola ed ha la capacità di 3 auto per volta(per cui e passano una/due/tre auto da una parte,dall'altra non possono passare). Ogni auto per attraversare il ponte impiega 100 ms. La classe ponte ha due metodi portanti : entra() ed esci().
La prima serve a chiedere l'accesso al ponte e ad attraversarlo, la seconda serve per uscire ed avvertire gli altri di essere usciti. L'auto deve avere due direzioni (nord o sud).

Questo è quello che sono riuscito a fare.


MAIN

codice:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package principale;

/**
 *
 * @author fabio
 */
public class Principale {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        
        Ponte ponte = new Ponte();
        Auto []auto = new Auto[10];
        
        for(int i=0;i<auto.length;i++){
            auto[i] = new Auto(ponte);
        }
        
        for(int i=0;i<auto.length;i++){
            auto[i].start();
        }
        
        try{
        for(int i=0;i<auto.length;i++){
            auto[i].join();
        }
        }catch(InterruptedException e){
            System.out.println(e);
        }
        
        
    }
}

OGGETTO CONDIVISO

codice:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package principale;

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 *
 * @author fabio
 */
public class Ponte {
    ReentrantLock lock;
    Semaphore macchine;
    Condition autoNord,autoSud;
    private int nordIn,sudIn;
    private int codaSud,codaNord;
    
    public Ponte(){
        this.lock = new ReentrantLock();
        this.macchine = new Semaphore(3);
        this.autoNord = this.lock.newCondition();
        this.autoSud = this.lock.newCondition();
        this.nordIn = 0;
        this.sudIn = 0;
        this.codaNord = 0;
        this.codaSud = 0;
    }
    
    
    public void Entra(int direzione){
        this.lock.lock();
        try{
            if(direzione == 0)
            {
                while(this.sudIn > 0)
                {
                    this.codaNord++;
                    System.out.println("Auto attende a nord");
                    this.autoNord.await();
                    this.codaNord--;
                }
                this.macchine.acquire();
                System.out.println("Auto entra da nord");
                this.nordIn++;
                
            }
            else 
            {
                while(this.nordIn > 0)
                {
                    this.codaSud++;
                    System.out.println("Auto attende a sud");
                    this.autoSud.await();
                    this.codaSud--;
                }
                this.macchine.acquire();
                System.out.println("Auto entra da sud");
                this.sudIn++;
                
            }
            
        }catch(InterruptedException e){
            System.out.println(e);
        }finally{
            this.lock.unlock();
        }
    }
    
    
    public void Esci(int direzione){
        this.lock.lock();
        try{
            
            if(direzione == 0)
            {
                this.nordIn--; 
                System.out.println("Auto esce da sud");
                this.macchine.release();
                
                if((nordIn == 0) && (codaSud >0))
                {
                    this.autoSud.signalAll();
                }   
                else
                    if(codaNord >0)
                    this.autoNord.signal();
            }
            else
            {
                this.sudIn--;
                System.out.println("Auto esce da nord");
                this.macchine.release();
                
                if((sudIn == 0) && (codaNord >0))
                {
                    this.autoNord.signalAll();
                }
                else
                    if(codaSud >0)
                        this.autoSud.signal();
            }
        }finally{
            this.lock.unlock();
        }
    }
    
}

THREAD

codice:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package principale;

import java.util.Random;

/**
 *
 * @author fabio
 */
public class Auto extends Thread{
    
    private Ponte ponte;
    Random rnd = new Random();
    
    public Auto(Ponte ponte){
        this.ponte = ponte;
    }
    
    @Override
    public void run(){
        
            int x = rnd.nextInt(2);
            this.ponte.Entra(x);
            try{
            sleep(1);
             }catch(InterruptedException e){
            System.out.println(e);
        }
            System.out.println("Provo ad uscire");
            this.ponte.Esci(x);
            
       
    }
}

Il programma gira senza errori. Il problema è che si blocca soltanto nel caso in cui ci sono 3 auto sul ponte che devono uscire, praticamente viene invocato il metodo esci ma il programma si blocca sul lock. Dove sbaglio?