1. Introducción
En este tutorial, discutiremos la interfaz de cola de Java .
Primero, echaremos un vistazo a lo que hace una cola y algunos de sus métodos principales . A continuación, profundizaremos en una serie de implementaciones que Java proporciona como estándar.
Por último, hablaremos sobre la seguridad de los subprocesos antes de terminar con todo.
2. Visualización de la cola
Comencemos con una analogía rápida.
Imagínese que acabamos de abrir nuestro primer negocio: un puesto de perritos calientes. Queremos servir a nuestros nuevos clientes potenciales de la manera más eficiente posible para nuestra pequeña empresa; uno a la vez. Primero, les pedimos que formen una fila ordenada frente a nuestro stand, con nuevos clientes uniéndose en la parte trasera. Gracias a nuestra capacidad organizativa, ahora podemos distribuir nuestros sabrosos hot dogs de forma justa.
Las colas en Java funcionan de manera similar. Después de declarar nuestra Cola, podemos agregar nuevos elementos al final y eliminarlos del frente.
De hecho, la mayoría de las colas que encontraremos en Java funcionan de esta manera de primero en entrar, primero en salir , a menudo abreviado como FIFO.
Sin embargo, hay una excepción que abordaremos más adelante.
3. Métodos básicos
La cola declara varios métodos que deben ser codificados por todas las clases de implementación. Resumamos ahora algunos de los más importantes :
- oferta () : inserta un nuevo elemento en la cola
- poll () : elimina un elemento del frente de la cola
- peek () : inspecciona el elemento al principio de la cola, sin eliminarlo
4. AbstractQueue
AbstractQueue es la implementación de cola más simple posible que proporciona Java. Incluye una implementación esquelética de algunos de los métodos de la interfaz de cola , excluyendo la oferta .
Cuando creamos una cola personalizada ampliando la clase AbstractQueue , debemos proporcionar una implementación del método de oferta que no permita la inserción de elementos nulos.
Además, debemos proporcionar los métodos peek, poll, size y el iterador de java.util .
Armemos una implementación de cola simple usando AbstractQueue.
Primero, definamos nuestra clase con una LinkedList para almacenar los elementos de nuestra Cola :
public class CustomBaeldungQueue extends AbstractQueue { private LinkedList elements; public CustomBaeldungQueue() { this.elements = new LinkedList(); } }
A continuación, anulemos los métodos requeridos y proporcionemos el código:
@Override public Iterator iterator() { return elements.iterator(); } @Override public int size() { return elements.size(); } @Override public boolean offer(T t) { if(t == null) return false; elements.add(t); return true; } @Override public T poll() { Iterator iter = elements.iterator(); T t = iter.next(); if(t != null){ iter.remove(); return t; } return null; } @Override public T peek() { return elements.getFirst(); }
Excelente, comprobemos que funciona con una prueba unitaria rápida:
customQueue.add(7); customQueue.add(5); int first = customQueue.poll(); int second = customQueue.poll(); assertEquals(7, first); assertEquals(5, second);
4. Subinterfaces
Generalmente, la interfaz de cola es heredada por 3 subinterfaces principales. Bloqueo de colas, colas de transferencia y deques .
Juntas, estas 3 interfaces son implementadas por la gran mayoría de las colas disponibles de Java . Echemos un vistazo rápido a lo que se han propuesto hacer estas interfaces.
4.1. Bloqueo de colas
La interfaz BlockingQueue admite operaciones adicionales que obligan a los subprocesos a esperar en la cola según el estado actual. Un hilo puede esperar en la Cola para no estar vacío cuando intenta una recuperación, o para que se vacíe cuando agrega un nuevo elemento.
Las colas de bloqueo estándar incluyen LinkedBlockingQueue, SynchronousQueue y ArrayBlockingQueue .
Para obtener más información, consulte nuestro artículo sobre bloqueo de colas .
4.2. Colas de transferencia
La interfaz TransferQueue amplía la interfaz BlockingQueue , pero se adapta al patrón productor-consumidor. Controla el flujo de información del productor al consumidor, creando contrapresión en el sistema.
Java se envía con una implementación de la interfaz TransferQueue , LinkedTransferQueue.
4.3. Deques
Deque es la abreviatura de D ouble- E nded Que UE y es análogo a una baraja de cartas - elementos pueden ser tomadas tanto desde el inicio y el final de la cola de doble extremo . Al igual que la tradicional cola, el deque proporciona métodos para añadir, recuperar y mirada a los elementos detenidos en la parte superior e inferior .
Para obtener una guía detallada sobre cómo funciona Deque , consulte nuestro artículo ArrayDeque .
5. Colas de prioridad
Vimos anteriormente que la mayoría de las colas que encontramos en Java siguen el principio FIFO.
Una de esas excepciones a esta regla es PriorityQueue . Cuando se insertan nuevos elementos en la cola de prioridad , se ordenan en función de su orden natural o mediante un comparador definido que se proporciona cuando construimos la cola de prioridad .
Echemos un vistazo a cómo funciona esto con una prueba unitaria simple:
PriorityQueue integerQueue = new PriorityQueue(); integerQueue.add(9); integerQueue.add(2); integerQueue.add(4); int first = integerQueue.poll(); int second = integerQueue.poll(); int third = integerQueue.poll(); assertEquals(2, first); assertEquals(4, second); assertEquals(9, third);
A pesar del orden en el que se agregaron nuestros números enteros a la cola de prioridad , podemos ver que el orden de recuperación cambia de acuerdo con el orden natural de los números.
Podemos ver que lo mismo también es cierto cuando se aplica a Strings :
PriorityQueue stringQueue = new PriorityQueue(); stringQueue.add("blueberry"); stringQueue.add("apple"); stringQueue.add("cherry"); String first = stringQueue.poll(); String second = stringQueue.poll(); String third = stringQueue.poll(); assertEquals("apple", first); assertEquals("blueberry", second); assertEquals("cherry", third);
6. Seguridad del hilo
Adding items to Queues is particularly useful in multi-threaded environments. A Queue can be shared amongst threads, and be used to block progress until space is available – helping us overcome some common multi-threaded problems.
For example, writing to a single disk from multiple threads creates resource contention and can lead to slow writing times. Creating a single writer thread with a BlockingQueue can alleviate this issue and lead to vastly improved write speeds.
Luckily, Java offers ConcurrentLinkedQueue, ArrayBlockingQueue, and ConcurrentLinkedDeque which are thread-safe and perfect for multi-threaded programs.
7. Conclusion
En este tutorial, hemos profundizado en la interfaz de Java Queue .
En primer lugar, hemos explorado lo que es una cola hace , así como las implementaciones que Java proporciona.
A continuación, analizamos el principio FIFO habitual de una cola , así como el PriorityQueue, que difiere en su orden.
Finalmente, exploramos la seguridad de los subprocesos y cómo se pueden utilizar las colas en un entorno de subprocesos múltiples.
Como siempre, el código está disponible en GitHub.