Un pont à sens unique avec des voitures venant des deux sens avec une interface graphique et une 

limite sur le nombre maximum de voitures consécutives dans une direction

Une classe interne - Gui - a été introduite dans la classe Bridge pour implémenter l'interface graphique. Il hérite de la classe Frame et contient 5 panneaux ::

Chaque voiture est placée sur le panneau correspondant avec un bouton étiqueté la lettre V et le numéro de série de la voiture. Le bouton est vert si la voiture doit traverser le pont de gauche à droite et jaune dans le sens opposé. Afin de pouvoir supprimer les boutons en quittant le panneau correspondant, trois ArraiList<Vehicle> sont maintenus pour les références des boutons dans les trois premiers panneaux. Le bouton est recherché dans une boucle par son étiquete.

Le panneau du pont est de couleur grise lorsque le pont est ouvert à la circulation et rose lorsqu'il est fermé.

Bridge  - la ressource partagée.

import java.awt.Color;
import java.util.ArrayList;
import javax.swing.*;

public class Bridge {
    private int nVh,cnt_cons, max_cons;
    private boolean closed;
    private Gui gui;
    Bridge(int max_cons){
        nVh = cnt_cons=0;
        closed = false;
        this.max_cons=max_cons;
        gui = new Gui();
    }
    ////////  for GUI  ----------------------------------
    public class Gui extends JFrame{
        int w=800,h=400;
        ArrayList<JButton> a_l=new ArrayList<JButton>();
        ArrayList<JButton> a_r=new ArrayList<JButton>();
        ArrayList<JButton> on=new ArrayList<JButton>();
        JPanel  pa_l= new JPanel(),  //on the left waiting
                pa_r= new JPanel(),  //on the right waiting
                pon= new JPanel(),   //on the bridge
                pp_l= new JPanel(),  //on the left passed
                pp_r= new JPanel();  //on the right passed

        Gui() {
            setBounds(50, 50, w, h);
            setLayout(null);

            pa_l.setBounds(10, 10, w/3, h/3);
            add(pa_l);

            pp_l.setBounds(10, h/3+50, w/3, h/2);
            add( pp_l);

            pon.setBackground(Color.LIGHT_GRAY);
            pon.setBounds(w/3+20, h/4, w/3-20, h/10);
            add(pon);

            pa_r.setBounds(2*w/3, 10, w/3, h/3);
            add(pa_r);

            pp_r.setBounds(2*w/3, h/3+50, w/3, h/2);
            add(pp_r);

            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setVisible(true);
        }
    }

    synchronized public void addGV(Vehicle v){  //gui new Vehicle
        JButton bt=new JButton(v.name);
        if(v.lr) {
            gui.pa_l.add(bt);
            bt.setBackground(Color.green);
            gui.pa_l.revalidate();
            gui.pa_l.repaint();
            gui.a_l.add(bt);
        }
        else {
            gui.pa_r.add(bt);
            bt.setBackground(Color.yellow);
            gui.pa_r.revalidate();
            gui.pa_r.repaint();
            gui.a_r.add(bt);
        }
    }
    synchronized public void onBGV(Vehicle v){  //gui on the bridge
        if(v.lr) {
            for(JButton b:gui.a_l){     //find on the list on the left      
                if(b.getText().equals(v.name)) {
                    gui.pa_l.remove(b);  // remove from panel left
                    gui.pon.add(b,0);   // put in the panel bridge at the start
                    gui.on.add(b);          // and on the list bridge
                    gui.pon.revalidate();
                    gui.pa_l.repaint();
                    gui.pa_l.revalidate();
                    gui.pon.repaint();
                    gui.a_l.remove(b);  //remove from the array on the left
                    break;
                }
            }       
        }
        else {
            for(JButton b:gui.a_r) {    //find on the list on the right
                if(b.getText().equals(v.name)) {
                    gui.pa_r.remove(b);  // remove from panel right
                    gui.pon.add(b);    // put in the panel on
                    gui.on.add(b);          // and on the list
                    gui.pon.revalidate();
                    gui.pon.repaint();
                    gui.pa_r.revalidate();
                    gui.pa_r.repaint();
                    gui.a_l.remove(b);  // remove from list
                    break;
                }
            }
        }        
    }

    synchronized public void lvBGV(Vehicle v){  //gui leave the bridge
        for(JButton b:gui.on) {
            if(b.getText().equals(v.name)) {
                gui.pon.remove(b);  // remove from panel
                gui.pon.revalidate();
                gui.pon.repaint();
                if(v.lr) {
                    gui.pp_r.add(b);         // put in the on
                    gui.pp_r.revalidate();
                    gui.pp_r.repaint();
                }
                else {
                    gui.pp_l.add(b);         // put in the on
                    gui.pp_l.revalidate();
                    gui.pp_l.repaint();
                }                
                break;
            }
        }       
    }
    synchronized public void closeB() {
        gui.pon.setBackground(Color.PINK);
        gui.pon.revalidate();
        gui.pon.repaint();
    }
    synchronized public void openB() {
        gui.pon.setBackground(Color.LIGHT_GRAY);
        gui.pon.revalidate();
        gui.pon.repaint();
    }

    ///////// Gui  ---------------------------------------------

    synchronized public int brN(){
        return nVh;
    }
    synchronized public void takeB(boolean lr ){
        while((nVh>0)&& (lr==true)||
                (nVh<0) && (lr==false)||closed){
            System.out.println("\t"+Thread.currentThread().getName()+" waiting");
            try{     wait();   }
            catch(InterruptedException e){
                System.err.println(e);
            }
        }
        try {
            Thread.sleep(1000);
        }
        catch(InterruptedException ie) {}
        if (lr) nVh--;
        else nVh++;
        System.out.println(Thread.currentThread().getName()+" on the bridge");
        onBGV((Vehicle)(Thread.currentThread()));
        cnt_cons++;
        if(cnt_cons>=max_cons) {
            closed =true;
            closeB();
        }
        if(closed)System.out.println("The bridge is closed");
    }
    synchronized public void leaveB(boolean lr ){
        if (nVh>0) nVh--;
        else nVh++;
        System.out.println("\t\t"+Thread.currentThread().getName()+" leave the bridge");
        lvBGV((Vehicle)Thread.currentThread());
        if(nVh==0) {
            cnt_cons=0;
            closed = false;
            openB();
            System.out.println("The bridge is open");
        }
        notifyAll();
    }
}

Vehicle - treads,

public class Vehicle extends Thread{
    boolean lr;
    Bridge b;
    String name;
    static int num;
    Vehicle(boolean lr, Bridge b){
        this.lr=lr;
        this.b = b;
        name = "V "+ ++num;
        b.addGV(this);
        super.setName(name); 
        if(lr) {
            System.out.println("new Vehicle on the left: "+ name);
        }
        else {
            System.out.println("new Vehicle on the right: "+ name);
        }
    }
    public void run(){
        b.takeB(lr);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e){}
        b.leaveB(lr);
    }
    public String toString() {
        return name;
    }
}

Application pour tester:

public class Circ {
    static Bridge b = new Bridge(3);
    public static void main(String arg[]){    
        for(int i = 0; i < 20; i++){
            Vehicle v =new Vehicle(Math.random()>0.5?true:false, b);         
            try {
                Thread.sleep(1000);
            }
            catch (InterruptedException ex) {}
            v.start();
        } 
    }
}