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