Traffic Light Problems (Producer/Consumer)

Asked

Viewed 1,345 times

1

Hello! I am trying to solve the Producer/Consumer Problem using semaphores, but I am struggling. I’m using one thread for producer and one for consumer, but I think the program is initiating the producer and it’s not doing the same to consumer. Could you tell me where the problem is? Thank you very much!

//Classe Principal
public class Principal {      

  public static void main(String[] args) {
    int N = 100;
    Semaphore mutex = new Semaphore(1);
    Semaphore vazio = new Semaphore(N);
    Semaphore cheio = new Semaphore(0);
    Fila fl = new Fila();

    Produtor produtor = new Produtor(mutex, vazio, cheio, fl);
    Consumidor consumidor = new Consumidor(mutex, vazio, cheio, fl);

    produtor.run();
    consumidor.run();
  }
}

//Classe do Produtor
public class Produtor extends Thread {
  Fila fl;
  Semaphore mutex, vazio, cheio;

  public Produtor(Semaphore mutex, Semaphore vazio, Semaphore cheio, Fila fl){
    this.mutex = mutex;
    this.vazio = vazio;
    this.cheio = cheio;
    this.fl = fl;
}

public void run(){
    int item;        
    while(true){
        try {
            Thread.sleep( ( int ) ( Math.random() * 3000 ) );
        } catch (InterruptedException ex) {
            Logger.getLogger(Produtor.class.getName()).log(Level.SEVERE, null, ex);
        }
        item = aleatorio(0, 99);
        this.vazio.down();
        this.mutex.down();
        this.fl.insere(item);
        this.mutex.up();
        this.cheio.up();
    }

}

  public int aleatorio(int minimo, int maximo) {
    Random random = new Random();
    return random.nextInt((maximo - minimo) + 1) + minimo;
  }
}

//Classe do Consumidor
public class Consumidor extends Thread {
  Fila fl;
  Semaphore mutex, vazio, cheio;

  public Consumidor(Semaphore mutex, Semaphore vazio, Semaphore cheio, Fila fl){
    this.mutex = mutex;
    this.vazio = vazio;
    this.cheio = cheio;
    this.fl = fl;
}

public void run() {
    int item;        
    while(true){
        try {
            Thread.sleep( ( int ) ( Math.random() * 3000 ) );
        } catch (InterruptedException ex) {
            Logger.getLogger(Consumidor.class.getName()).log(Level.SEVERE, null, ex);
        }
        this.cheio.down();
        this.mutex.down();
        item = (int)this.fl.remove();
        this.mutex.up();
        this.vazio.up();
        System.out.println(item);
    }
  }
} 

//Classe do Semáforo
public class Semaphore {
  private int count = 0;

  public Semaphore(int initVal) {
    count = initVal;
  }

  public synchronized void down() {
    if (count > 0){
        count--;
    } else {
        try {        /* esperar até que count > 0 */
            wait();
        } catch (InterruptedException e) { 
            System.out.println("erro");
        }  
    }

  }

  public synchronized void up() {
    count++;
    notify(); /* acordar quem estiver em espera */
  } 
}

//Classe Fila para armazenar os elemenetos
public class Fila<T> {
  private List<T> objetos = new LinkedList<T>();

  public void insere(T t){
    this.objetos.add(t);
  }

  public T remove(){
    return this.objetos.remove(0);
  }

  public boolean vazia(){
    return this.objetos.size() == 0;
  }
}

1 answer

2


Running the thread by the method run, ie, will execute the code of this method in the current thread without creating a new thread (like any other method). Therefore the run consumer will only perform when the run of the producer terminating, ie never in that example.

You should use the method start which creates a new thread and executes the run in this new thread, returning from start in the current thread:

public static void main(String[] args) {
    ...
    produtor.start();   // executa o run numa nova thread
    consumidor.start();
}

Additional information: instead of extending Thread it is more appropriate to implement Runnable and pass it in the Thread constructor:

class Produtor implementes Runnable {
    ...
    public void run() {
        ...
    }
}

Use:

    Produtor produtor = new Produtor(...);
    Thead produtorThread = new Thread(produtor);
    produtorThread.start();

More information: Threads

Update: with the use of Lambda, especially for less complicated functions it is not necessary to create a dedicated class:

    Thead produtorThread = new Thread( () -> {
        // comandos a serem executados
        } );
    produtorThread.start();

or, using a reference to a method (my favorite):

public class Principal {
...
    Thread produtorThread = new Thread(Principal::metodo); // ou this::metodo para métodos não-static
    produtorThread.start();
...
private static void metodo() {
    // comandos a serem executados na Thread
}
  • Thank you so much for your help Carlos.

  • Yes, very good explanation. Thank you!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.