Ejemplo de Java BlockingQueue

Hoy vamos a analizar Java BlockingQueue. `java.util.concurrent.BlockingQueue` es una cola de Java que admite operaciones que esperan a que la cola se vuelva no vacía al recuperar y eliminar un elemento, y esperan a que haya espacio disponible en la cola al agregar un elemento.

Java BlockingQueue

Java BlockingQueue no acepta valores `null` y lanza una `NullPointerException` si intenta almacenar un valor nulo en la cola. Las implementaciones de Java BlockingQueue son seguras para subprocesos. Todos los métodos de encolado son atómicos por naturaleza y utilizan bloqueos internos u otras formas de control de concurrencia. La interfaz Java BlockingQueue es parte del marco de colecciones de Java y se utiliza principalmente para implementar el problema del productor-consumidor. No necesitamos preocuparnos por esperar a que haya espacio disponible para el productor o que el objeto esté disponible para el consumidor en BlockingQueue porque lo manejan las clases de implementación de BlockingQueue. Java proporciona varias implementaciones de BlockingQueue como `ArrayBlockingQueue`, `LinkedBlockingQueue`, `PriorityBlockingQueue`, `SynchronousQueue`, etc. Al implementar el problema del productor-consumidor en BlockingQueue, utilizaremos la implementación ArrayBlockingQueue. A continuación, se muestran algunos métodos importantes que debes conocer.

  • put(E e): Este método se utiliza para insertar elementos en la cola. Si la cola está llena, espera a que haya espacio disponible.
  • E take(): This method retrieves and remove the element from the head of the queue. If queue is empty it waits for the element to be available.

Ahora implementemos el problema del productor-consumidor utilizando BlockingQueue en Java.

Ejemplo de BlockingQueue en Java – Mensaje

Solo un objeto Java normal que será producido por el Productor y añadido a la cola. También puedes llamarlo carga útil o mensaje de cola.

package com.journaldev.concurrency;

public class Message {
    private String msg;
    
    public Message(String str){
        this.msg=str;
    }

    public String getMsg() {
        return msg;
    }

}

Ejemplo de BlockingQueue en Java – Productor

Clase Productor que creará mensajes y los colocará en la cola.

package com.journaldev.concurrency;

import java.util.concurrent.BlockingQueue;

public class Producer implements Runnable {

    private BlockingQueue queue;
    
    public Producer(BlockingQueue q){
        this.queue=q;
    }
    @Override
    public void run() {
        // producir mensajes
        for(int i=0; i<100; i++){
            Message msg = new Message(""+i);
            try {
                Thread.sleep(i);
                queue.put(msg);
                System.out.println("Produced "+msg.getMsg());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // añadir mensaje de salida
        Message msg = new Message("exit");
        try {
            queue.put(msg);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

Ejemplo de BlockingQueue en Java – Consumidor

Clase Consumidor que procesará los mensajes de la cola y terminará cuando reciba el mensaje de salida.

package com.journaldev.concurrency;

import java.util.concurrent.BlockingQueue;

public class Consumer implements Runnable{

private BlockingQueue queue;
    
    public Consumer(BlockingQueue q){
        this.queue=q;
    }

    @Override
    public void run() {
        try{
            Message msg;
            // consumir mensajes hasta que se reciba el mensaje de salida
            while((msg = queue.take()).getMsg() !="exit"){
            Thread.sleep(10);
            System.out.println("Consumed "+msg.getMsg());
            }
        }catch(InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Ejemplo de BlockingQueue en Java – Servicio

Finalmente, tenemos que crear un servicio BlockingQueue para el productor y el consumidor. Este servicio productor-consumidor creará la BlockingQueue con tamaño fijo y la compartirá tanto con los productores como con los consumidores. Este servicio iniciará los hilos del productor y del consumidor y luego terminará.

package com.journaldev.concurrency;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ProducerConsumerService {

    public static void main(String[] args) {
        // Creando BlockingQueue de tamaño 10
        BlockingQueue queue = new ArrayBlockingQueue<>(10);
        Producer producer = new Producer(queue);
        Consumer consumer = new Consumer(queue);
        // iniciando el productor para producir mensajes en la cola
        new Thread(producer).start();
        // iniciando el consumidor para consumir mensajes de la cola
        new Thread(consumer).start();
        System.out.println("Producer and Consumer has been started");
    }

}

La salida del programa de ejemplo de BlockingQueue en Java anterior se muestra a continuación.

Producer and Consumer has been started
Produced 0
Produced 1
Produced 2
Produced 3
Produced 4
Consumed 0
Produced 5
Consumed 1
Produced 6
Produced 7
Consumed 2
Produced 8
...

La función Java Thread sleep se utiliza en el productor y el consumidor para producir y consumir mensajes con cierto retraso.

Source:
https://www.digitalocean.com/community/tutorials/java-blockingqueue-example