Implementación de Patrón Productor-Consumidor con Hilos en Java

Enviado por Chuletator online y clasificado en Informática y Telecomunicaciones

Escrito el en español con un tamaño de 5,64 KB

Implementación de Sistema de Producción y Empaquetado con Hilos

A continuación, se presenta el código fuente corregido y formateado, enfocado en la implementación del patrón Productor-Consumidor utilizando hilos en Java para simular el ensamblaje y empaquetado de hamburguesas.

Clase RobotEmpaquetador (Consumidor)

Esta clase representa a los robots encargados de tomar y empaquetar un tipo específico de hamburguesa del mostrador compartido.

class RobotEmpaquetador extends Thread {
    private Mostrador buff;
    private String tipoHamburguesa;

    // En el constructor se recibe el objeto Mostrador, que es compartido
    public RobotEmpaquetador(Mostrador buff, String tipoHamburguesa) {
        this.buff = buff;
        this.tipoHamburguesa = tipoHamburguesa;
    }

    @Override
    public void run() {
        // Para toda la vida
        while(true) {
            // Esperamos un tiempo y consumimos
            try {
                Thread.sleep(95);
                // Este robot concreto debe consumir el tipo de hamburguesa que ha recibido
                // en el constructor
                buff.consumir(tipoHamburguesa);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

Clase RobotEnsamblador (Productor)

Este hilo se encarga de producir aleatoriamente una de las hamburguesas disponibles y colocarla en el mostrador.

class RobotEnsamblador extends Thread {
    private Mostrador buff;
    private String[] opciones = {"smash", "vegan", "chicken"};

    // En el constructor se recibe el objeto Mostrador, que es compartido
    public RobotEnsamblador(Mostrador buff) {
        this.buff = buff;
    }

    @Override
    public void run() {
        while (true) {
            // Esperamos un tiempo y producimos
            try {
                Thread.sleep((int)(Math.random() * 31) + 20);
                // Saco aleatoriamente una hamburguesa de entre las 3 que hay cada vez
                // y trato de empaquetarla
                String hamburguesAProducir = opciones[(int)(Math.random() * opciones.length)];
                buff.producir(hamburguesAProducir);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Clase Mostrador (Buffer Compartido)

Esta clase actúa como el buffer compartido y gestiona la sincronización entre productores y consumidores mediante los métodos wait() y notifyAll().

Métodos de Sincronización

  • producir(String contenido): Añade una hamburguesa si hay espacio. Si el mostrador está lleno, el hilo espera.
  • consumir(String tipoHamburguesaACoger): Intenta retirar una hamburguesa específica. Si el mostrador está vacío o no contiene el tipo solicitado, el hilo espera.
// Objeto compartido (buffer)
class Mostrador {
    private int elementosMax;
    private ArrayList<String> cola = new ArrayList<>();

    public Mostrador(int elementosMax) {
        this.elementosMax = elementosMax;
    }

    public synchronized void producir(String contenido) {
        // Compruebo si el mostrador está lleno, en cuyo caso me espero porque no hay hueco
        while(this.cola.size() == elementosMax) {
            try {
                System.out.println("😢 Esperando que haya hueco en el mostrador para ensamblar una nueva hamburguesa...");
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // Si estoy aquí es que hay hueco, produzco la hamburguesa
        this.cola.add(contenido);
        System.out.println("🍔 Ensamblada: "+contenido);
        // Notifico a los hilos para que se despierten y puedan ensamblar
        notifyAll();
    }

    public synchronized void consumir(String tipoHamburguesaACoger) {
        // En caso de que no haya ninguna hamburguesa
        // o bien no exista del tipo que quiero empaquetar, me quedo esperando
        while(this.cola.isEmpty()  || !this.cola.contains(tipoHamburguesaACoger)) {
            try {
                System.out.println("⌚ Esperando a que haya una "+tipoHamburguesaACoger+" para poder empaquetarla...");
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // Si estoy aquí es que hay una hamburguesa para empaquetar en el mostrador
        this.cola.remove(tipoHamburguesaACoger);
        System.out.println("🍴 Empaquetada: "+tipoHamburguesaACoger);

        // Notifico al hilo para que se despierte y puedan producir en el nuevo hueco
        notifyAll();
    }
}

Clase Principal RoboBurguer

Configuración inicial y arranque de todos los hilos concurrentes.

public class RoboBurguer {
    public static void main(String[] args) {
        // Creo los elementos de mi programa
        Mostrador mostrador = new Mostrador(10);
        
        // Inicialización de Robots Empaquetadores (Consumidores)
        Thread emp1 = new RobotEmpaquetador(mostrador, "vegan");
        Thread emp2 = new RobotEmpaquetador(mostrador, "chicken");
        Thread emp3 = new RobotEmpaquetador(mostrador, "smash");
        
        // Inicialización de Robot Ensamblador (Productor)
        Thread ens = new RobotEnsamblador(mostrador);
        
        // Los arranco
        emp1.start();
        emp2.start();
        emp3.start();
        ens.start();
    }
}

Entradas relacionadas: