A one-way bridge with cars coming from both directions with a graphical interface and
limit on the maximum number of consecutive cars in one direction

An internal class - Gui - has been introduced in the Bridge class to implement the GUI. It is derived from the Frame class and contains 5 panels::

     * for cars coming from the left;
     * for cars coming from the right;
     * for cars on the bridge;
     * for cars on the right (which have crossed the bridge);
     * for cars on the left (which have crossed the bridge);

Each car is placed on the corresponding panel with a button labeled the letter V and the car's serial number. The button is green if the car must cross the bridge from left to right and yellow in the opposite direction. In order to be able to delete the buttons when leaving the corresponding panel, three ArrayLists<Vehicle> are maintained for the button references in the first three panels. The button is searched in a loop by its label.

The bridge sign is colored gray when the bridge is open to traffic and pink when closed.

Bridge - the shared resource.

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{
        private static final long serialVersionUID = 1L;
        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();
    }
}

Vehicles - threads,

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 to test:

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();
        } 
    }
}