import java.util.Vector;
import java.util.concurrent.Semaphore;

public class SemPC{
    public static final int N = 10;
    public static final void main(final String[] args) {
        Vector<Object> shared = new Vector<Object>(N);
        Semaphore mutex = new Semaphore(1);
        Semaphore empty = new Semaphore(N);
        Semaphore full = new Semaphore(0);
        Producer p = new Producer(shared, mutex, empty, full);
        Consumer c = new Consumer(shared, mutex, empty, full);
        p.start(); c.start();
    }
}

class Agent extends Thread{
    protected Vector<Object> buf;
    protected Semaphore mutex;
    protected Semaphore empty;
    protected Semaphore full;
    public Agent(String name, Vector<Object> b, 
                 Semaphore _mutex, Semaphore _empty, Semaphore _full){
        super(name);
        this.buf = b;
        this.mutex = _mutex;
        this.full = _full;
        this.empty = _empty;
    }
}

class Producer extends Agent{
    public Producer(Vector<Object> b, 
                    Semaphore _mutex, Semaphore _empty, Semaphore _full) { 
        super("Producer", b, _mutex, _empty, _full); 
    }
    public void run(){
        while (true){
            Object o = new Object();
            System.out.println("Ho prodotto " + o);
            try {
                this.empty.acquire();
                this.mutex.acquire();
                this.buf.add(o);
                this.mutex.release();
                this.full.release();
            } catch (InterruptedException e) {
                System.err.println(e);
            }
        }
    }
}

class Consumer extends Agent{
    public Consumer(Vector<Object> b,
                    Semaphore _mutex, Semaphore _empty, Semaphore _full) { 
        super("Consumer", b, _mutex, _empty, _full); }
    public void run(){
        while (true){
            try {
                this.full.acquire();
                this.mutex.acquire();
                Object o = this.buf.remove(0);
                System.out.println("Ho consumato " + o);
                this.mutex.release();
                this.empty.release();
            } catch (InterruptedException e) {
                System.out.println(e);
            }
        }
    }
}
   