Filas sem Bloqueio
Implementações de fila seguras para threads e, o mais importante, sem bloqueio em nós vinculados.
ConcurrentLinkedQueue<E> - usa um algoritmo sem espera adaptado para trabalhar com o coletor de lixo. Este algoritmo é bastante eficiente e muito rápido, pois é construído sobre o CAS. O método size() pode ser executado por um longo período de tempo, portanto, é melhor não puxá-lo o tempo todo.
ConcurrentLinkedDeque<E> - Deque significa Fila dupla. Isso significa que os dados podem ser adicionados e extraídos de ambos os lados. Assim, a classe suporta ambos os modos de operação: FIFO (First In First Out) e LIFO (Last In First Out).
Na prática, ConcurrentLinkedDeque deve ser utilizado caso o LIFO seja absolutamente necessário, pois devido à bidirecionalidade dos nós, esta classe perde metade do desempenho em relação a ConcurrentLinkedQueue .
import java.util.concurrent.ConcurrentLinkedQueue;
public class ConcurrentLinkedQueueExample {
public static void main(String[] args) {
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
Thread producer = new Thread(new Producer(queue));
Thread consumer = new Thread(new Consumer(queue));
producer.start();
consumer.start();
}
}
class Producer implements Runnable {
ConcurrentLinkedQueue<String> queue;
Producer(ConcurrentLinkedQueue<String> queue){
this.queue = queue;
}
public void run() {
System.out.println("Class for adding items to the queue");
try {
for (int i = 1; i < 5; i++) {
queue.add("Item #" + i);
System.out.println("Added: Item #" + i);
Thread.sleep(300);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
class Consumer implements Runnable {
ConcurrentLinkedQueue<String> queue;
Consumer(ConcurrentLinkedQueue<String> queue){
this.queue = queue;
}
public void run() {
String str;
System.out.println("Class for getting items from the queue");
for (int x = 0; x < 5; x++) {
while ((str = queue.poll()) != null) {
System.out.println("Pulled out: " + str);
}
try {
Thread.sleep(600);
} catch (InterruptedException ex) {
ex.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
}
Bloqueio de Filas
Interface BlockingQueue<E> - se houver muitos dados, ConcurrentLinkedQueue não será suficiente.
Quando os threads falham em fazer seu trabalho, você pode facilmente obter um OutOfMemmoryException . E para que esses casos não ocorram, temos um BlockingQueue para trabalhar com a presença de diferentes métodos de preenchimento e trabalho com a fila e bloqueios condicionais.
BlockingQueue não reconhece elementos nulos e lança um NullPointerException ao tentar adicionar ou obter tal elemento. O método poll retorna um elemento nulo se nenhum elemento foi colocado na fila dentro do tempo limite.
Implementações BlockingQueue<E>
Vamos dar uma olhada em cada uma de nossas implementações BlockingQueue :
ArrayBlockingQueue<E> é uma classe de fila de bloqueio criada no buffer de anel clássico. Aqui temos a oportunidade de gerir a “honestidade” das fechaduras. Se justo=falso (o padrão), a ordem do encadeamento não é garantida.
DelayQueue<E extends Delayed> é uma classe que permite puxar elementos da fila somente após um certo atraso, definido em cada elemento através do método getDelay da interface Delayed .
LinkedBlockingQueue<E> é uma fila de bloqueio em nós vinculados, implementada no algoritmo “two lock queue”: o primeiro bloqueio é para adicionar, o segundo é para puxar um elemento da fila. Devido aos bloqueios, em comparação com ArrayBlockingQueue , esta classe tem alto desempenho, mas requer mais memória. O tamanho da fila é definido por meio do construtor e é igual a Integer.MAX_VALUE por padrão.
PriorityBlockingQueue<E> é um wrapper multiencadeado sobre PriorityQueue . O Comparator é responsável pela lógica pela qual o elemento será adicionado. O menor elemento sai primeiro.
SynchronousQueue<E> - a fila funciona de acordo com o princípio FIFO (first-in-first-out). Cada operação de inserção bloqueia o thread “Produtor” até que o segmento “Consumidor” puxe o elemento da fila e vice-versa, o “Consumidor” aguardará até que o “Produtor” insira o elemento.
BlockingDeque<E> é uma interface que descreve métodos adicionais para uma fila de bloqueio bidirecional. Os dados podem ser inseridos e retirados de ambos os lados da fila.
LinkedBlockingDeque<E> é uma fila de bloqueio bidirecional em nós vinculados, implementada como uma lista bidirecional simples com um bloqueio. O tamanho da fila é definido por meio do construtor e é igual a Integer.MAX_VALUE por padrão.
TransferQueue<E> - a interface é interessante porque, quando um elemento é adicionado à fila, é possível bloquear a inserção do encadeamento do produtor até que outro encadeamento do consumidor extraia o elemento da fila. Você também pode adicionar uma verificação para um tempo limite específico ou definir uma verificação para Consumer s pendentes . Como resultado, obtemos um mecanismo de transferência de dados com suporte para mensagens assíncronas e síncronas.
LinkedTransferQueue<E> é uma implementação de TransferQueue baseada no algoritmo Dual Queues with Slack. Faz uso intenso de CAS (veja acima) e thread parking quando ocioso.
GO TO FULL VERSION