Abordagem usando wait-notify:
A classe Buffer implementa o armaeznamento de itens produzidos, controlando operações de inserção e remoção.
import java.util.LinkedList;
import static java.lang.Thread.sleep;
public class Buffer {
private final int CAPACIDADE_MAXIMA = 10;
private LinkedList<Object> itens = new LinkedList<>();
/**
* @param valor Identificador do produto a ser produzido
* @param tempo Tempo necessário para produção em segundos
*/
public void produzir(int valor, int tempo) {
synchronized (itens) {
while (itens.size() == CAPACIDADE_MAXIMA) {
System.out.println("Armazém cheio (" + CAPACIDADE_MAXIMA + " itens). Não é possível adicionar mais.");
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
itens.add(valor);
try {
sleep(tempo * 1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
System.out.println("Tempo de produção: " + tempo + " segundos");
}
System.out.println("Produtor " + Thread.currentThread().getName() + " adicionou item. Total: " + itens.size());
System.out.println("----------------------------------------");
itens.notifyAll();
}
}
/**
* Método correspondente à operação de consumo
* @param tempo Tempo necessário para consumo em segundos
*/
public void consumir(int tempo) {
synchronized (itens) {
while (itens.isEmpty()) {
System.out.println("Nenhum item no armazém. Aguardando produção...");
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
itens.removeFirst();
try {
sleep(tempo * 1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
System.out.println("Tempo de consumo: " + tempo + " segundos");
}
System.out.println("Consumidor " + Thread.currentThread().getName() + " removeu item. Total: " + itens.size());
System.out.println("----------------------------------------");
itens.notifyAll();
}
}
}
BufferA classe Producer executa a operação de produção:
public class Produtor implements Runnable {
private Buffer buffer;
private String nomeProdutor;
public Produtor(Buffer buffer) {
this.buffer = buffer;
}
public String getNomeProdutor() {
return nomeProdutor;
}
public void setNomeProdutor(String nomeProdutor) {
this.nomeProdutor = nomeProdutor;
}
@Override
public void run() {
buffer.produzir((int)(Math.random() * 10), (int)(Math.random() * 10));
}
}
ProdutorA classe Consumer realiza a operação de consumo:
public class Consumidor implements Runnable {
private Buffer buffer;
private String nomeConsumidor;
public Consumidor(Buffer buffer) {
this.buffer = buffer;
}
public String getNomeConsumidor() {
return nomeConsumidor;
}
public void setNomeConsumidor(String nomeConsumidor) {
this.nomeConsumidor = nomeConsumidor;
}
@Override
public void run() {
buffer.consumir((int)(Math.random() * 10));
}
}
ConsumidorA classe Teste contém o método principal para testar a funcionalidade:
public class Teste {
public static void main(String[] args) {
Buffer buffer = new Buffer();
Thread produtor1 = new Thread(new Produtor(buffer));
Thread produtor2 = new Thread(new Produtor(buffer));
Thread produtor3 = new Thread(new Produtor(buffer));
Thread produtor4 = new Thread(new Produtor(buffer));
Thread consumidor1 = new Thread(new Consumidor(buffer));
Thread consumidor2 = new Thread(new Consumidor(buffer));
Thread consumidor3 = new Thread(new Consumidor(buffer));
Thread consumidor4 = new Thread(new Consumidor(buffer));
produtor1.start();
produtor2.start();
produtor3.start();
produtor4.start();
consumidor1.start();
consumidor2.start();
consumidor3.start();
consumidor4.start();
}
}
Teste