Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprenda BlockingQueue e Suas Implementações | Coleções Sincronizadas
Multithreading em Java

bookBlockingQueue e Suas Implementações

Implementações Básicas de BlockingQueue

Não abordaremos cada realização em detalhes, pois isso levaria muito tempo e é improvável que você precise de todas. Vou falar sobre os conceitos gerais e quais construtores elas possuem.

Exemplo da Vida Real

Imagine uma fábrica onde uma thread, o produtor, cria peças, e outra thread, o consumidor, as processa. O produtor coloca as peças em uma fila, enquanto o consumidor as retira e processa da fila. Se a fila ficar sem peças, o consumidor espera o produtor adicionar mais. Por outro lado, se a fila estiver cheia, o produtor espera o consumidor liberar espaço.

Note
Nota

Logo abaixo, iremos implementar esta tarefa em código.

Diferenças em relação a outros tipos de coleção

A BlockingQueue fornece sincronização automatizada, gerenciando o acesso das threads à fila sem exigir sincronização manual. Também suporta operações de bloqueio para adicionar e recuperar itens, um recurso inexistente em outras coleções como ArrayList ou LinkedList.

Implementações de BlockingQueue

ArrayBlockingQueue: Uma fila limitada em tamanho que utiliza um array para armazenar os itens.

Main.java

Main.java

copy
123456789
// Constructor with fixed capacity BlockingQueue<String> queue1 = new ArrayBlockingQueue<>(5); // Constructor with fixed capacity and fair access BlockingQueue<String> queue2 = new ArrayBlockingQueue<>(5, true); // Constructor with fixed capacity and initial collection of elements Collection<String> initialElements = java.util.Arrays.asList("One", "Two", "Three"); BlockingQueue<String> queue3 = new ArrayBlockingQueue<>(5, false, initialElements);
Note
Nota

O parâmetro true habilita uma política de acesso justa ao fornecer uma ordem FIFO para o acesso das threads.

LinkedBlockingQueueue: Uma fila baseada em nós encadeados que pode ser restrita ou irrestrita.

Main.java

Main.java

copy
123456789
// Constructor without capacity bounds BlockingQueue<String> queue1 = new LinkedBlockingQueue<>(); // Constructor with fixed capacity BlockingQueue<String> queue2 = new LinkedBlockingQueue<>(5); // Constructor with initial collection of elements Collection<String> initialElements = java.util.Arrays.asList("One", "Two", "Three"); BlockingQueue<String> queue3 = new LinkedBlockingQueue<>(initialElements);

PriorityBlockingQueue: Uma fila prioritária sem limite onde os elementos são recuperados de acordo com sua ordem natural ou conforme especificado por um comparador.

Main.java

Main.java

copy
12345678910111213
// Constructor without initial capacity (default is 11) BlockingQueue<Integer> queue1 = new PriorityBlockingQueue<>(); // Constructor with initial capacity BlockingQueue<Integer> queue2 = new PriorityBlockingQueue<>(5); // Constructor with initial capacity and comparator Comparator<Integer> comparator = Integer::compareTo; BlockingQueue<Integer> queue3 = new PriorityBlockingQueue<>(5, comparator); // Constructor with initial collection of elements Collection<Integer> initialElements = java.util.Arrays.asList(1, 3, 2); BlockingQueue<Integer> queue4 = new PriorityBlockingQueue<>(initialElements)

DelayQueue: Uma fila atrasada onde os itens só podem ser recuperados após o vencimento do seu tempo de atraso.

DelayedElement.java

DelayedElement.java

DelayQueueConstructors.java

DelayQueueConstructors.java

copy
123456789101112131415161718
class DelayedElement implements Delayed { private final long expirationTime; // The time when the element will be available public DelayedElement(long delay, TimeUnit unit) { this.expirationTime = System.currentTimeMillis() + unit.toMillis(delay); } @Override public long getDelay(TimeUnit unit) { long delay = expirationTime - System.currentTimeMillis(); // Calculate the remaining delay return unit.convert(delay, TimeUnit.MILLISECONDS); // Convert the delay to the specified time unit } @Override public int compareTo(Delayed o) { return Long.compare(this.expirationTime, ((DelayedElement) o).expirationTime); } }

Este código demonstra o uso da classe DelayedElement, que implementa a interface Delayed, e da fila de atraso DelayQueue em Java. A classe DelayedElement define um método getDelay para calcular o tempo de atraso restante e um método compareTo para comparar objetos com base no tempo de expiração do atraso.

O método main cria duas filas: queue1, uma fila de atraso vazia, e queue2, uma fila inicializada com elementos que possuem atraso de 5 e 1 segundo, respectivamente.

Os itens em DelayQueueue tornam-se disponíveis para recuperação após o tempo de atraso especificado ter decorrido.

SynchronousQueueue: Uma fila sem capacidade, onde cada operação de inserção deve aguardar a correspondente operação de extração e vice-versa.

Main.java

Main.java

copy
12345
// Constructor without fair access BlockingQueue<String> queue1 = new SynchronousQueue<>(); // Constructor with fair access BlockingQueue<String> queue2 = new SynchronousQueue<>(true);

Principais métodos do BlockingQueue:

Adição de elementos:

O método void put(E e) insere um item na fila, bloqueando a thread se a fila estiver cheia. Alternativamente, o método boolean offer(E e, long timeout, TimeUnit unit) tenta adicionar um item à fila, aguardando pelo tempo especificado caso a fila esteja cheia.

Main.java

Main.java

copy
1234567891011121314151617
public class BlockingQueueExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { queue.put("Element 1"); // Insert the first element, no blocking. queue.put("Element 2"); // Insert the second element, no blocking. // Try to add the third element with a 2-second timeout. // Since the queue is full, it will wait for 2 seconds. boolean success = queue.offer("Element 3", 2, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } } }

Este exemplo demonstra a inserção de dois elementos em uma BlockingQueue sem bloqueio, seguida de uma tentativa de adicionar um terceiro elemento com um timeout de 2 segundos usando o método offer(), que aguardará caso a fila esteja cheia.

Recuperação de Elementos:

O método E take() recupera e retorna um item da fila, bloqueando a thread caso a fila esteja vazia. Alternativamente, o método E poll(long timeout, TimeUnit unit) tenta recuperar um item da fila, aguardando pelo tempo especificado caso a fila esteja vazia.

Main.java

Main.java

copy
1234567891011121314151617181920212223
public class BlockingQueueRetrievalExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Retrieve and remove the first element, no blocking since the queue is not empty String item1 = queue.take(); // Returns "Element 1" // Attempt to retrieve and remove the next element with a 2-second timeout String item2 = queue.poll(2, TimeUnit.SECONDS); // Returns "Element 2" // Attempt to retrieve an element when the queue is empty, this will block for 2 seconds String item3 = queue.poll(2, TimeUnit.SECONDS); // Returns `null` after timeout } catch (InterruptedException e) { e.printStackTrace(); } } }

Este código adiciona dois elementos a uma BlockingQueue, recupera e remove o primeiro elemento imediatamente, tenta recuperar o próximo elemento com um timeout de 2 segundos e, por fim, tenta recuperar um elemento de uma fila vazia, o que resulta em null após o tempo limite.

Verificação e Remoção de Elementos:

O método boolean remove(Object o) remove o elemento especificado da fila, se estiver presente. Por outro lado, o método boolean contains(Object o) verifica se o elemento especificado está presente na fila sem removê-lo.

Main.java

Main.java

copy
1234567891011121314151617181920212223242526
public class BlockingQueueCheckRemoveExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Check if "Element 1" is in the queue, should return `true` boolean containsElement1 = queue.contains("Element 1"); // true // Remove "Element 1" from the queue, should return `true` boolean removedElement1 = queue.remove("Element 1"); // true // Check if "Element 1" is still in the queue, should return `false` boolean containsElement1AfterRemoval = queue.contains("Element 1"); // false // Try to remove an element that is not in the queue, should return `false` boolean removedElement3 = queue.remove("Element 3"); // false } catch (InterruptedException e) { e.printStackTrace(); } } }

Este código adiciona dois elementos a uma BlockingQueue, verifica a presença de "Element 1", remove-o, verifica novamente para confirmar sua remoção e então tenta remover um elemento inexistente.

Consulta o Estado da Fila:

O método int size() retorna o número de elementos atualmente na fila. Para determinar se a fila está vazia, pode-se utilizar o método boolean isEmpty(), que verifica se a fila não possui elementos. Para filas com capacidade fixa, o método int remainingCapacity() fornece o número de espaços restantes disponíveis na fila.

Main.java

Main.java

copy
123456789101112131415161718192021222324252627282930
public class BlockingQueueCapacityExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(3); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Get the number of elements in the queue int currentSize = queue.size(); // 2 // Check if the queue is empty boolean isQueueEmpty = queue.isEmpty(); // false // Get the remaining capacity in the queue int remainingSpace = queue.remainingCapacity(); // 1 // Add another element to fill the queue queue.put("Element 3"); // Check the size and remaining capacity after adding the third element currentSize = queue.size(); // 3 remainingSpace = queue.remainingCapacity(); // 0 } catch (InterruptedException e) { e.printStackTrace(); } } }

Este código adiciona elementos a uma BlockingQueue, verifica o tamanho atual, verifica se a fila está vazia e determina a capacidade restante, depois atualiza esses valores após preencher completamente a fila.

Realizando um Exemplo da Vida Real em Código

😭 Limitações

Uma limitação importante é o desempenho: devido às operações de bloqueio envolvidas, o desempenho pode ser reduzido em comparação com coleções não sincronizadas. Além disso, recursos podem se tornar uma preocupação, pois filas grandes exigem mais memória e tempo de CPU para lidar com os bloqueios e os processos de sincronização.

💪 Vantagens

Por outro lado, o sistema é seguro em multithread, oferecendo comunicação segura entre threads sem exigir gerenciamento manual de sincronização. Também simplifica o código ao evitar construções complexas de sincronização e bloqueio. Além disso, a flexibilidade das diferentes implementações de BlockingQueue permite que sejam adequadas para vários cenários de uso.

1. O que é uma BlockingQueue em Java?

2. Quais são os principais métodos do BlockingQueue que bloqueiam uma thread?

3. Para que serve o BlockingQueue em aplicações multithread?

question mark

O que é uma BlockingQueue em Java?

Select the correct answer

question mark

Quais são os principais métodos do BlockingQueue que bloqueiam uma thread?

Select the correct answer

question mark

Para que serve o BlockingQueue em aplicações multithread?

Select the correct answer

Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 2. Capítulo 3

Pergunte à IA

expand

Pergunte à IA

ChatGPT

Pergunte o que quiser ou experimente uma das perguntas sugeridas para iniciar nosso bate-papo

Suggested prompts:

What are the main differences between the BlockingQueue implementations?

Can you explain how the DelayQueue works in more detail?

How does the producer-consumer example work in code?

Awesome!

Completion rate improved to 3.33

bookBlockingQueue e Suas Implementações

Deslize para mostrar o menu

Implementações Básicas de BlockingQueue

Não abordaremos cada realização em detalhes, pois isso levaria muito tempo e é improvável que você precise de todas. Vou falar sobre os conceitos gerais e quais construtores elas possuem.

Exemplo da Vida Real

Imagine uma fábrica onde uma thread, o produtor, cria peças, e outra thread, o consumidor, as processa. O produtor coloca as peças em uma fila, enquanto o consumidor as retira e processa da fila. Se a fila ficar sem peças, o consumidor espera o produtor adicionar mais. Por outro lado, se a fila estiver cheia, o produtor espera o consumidor liberar espaço.

Note
Nota

Logo abaixo, iremos implementar esta tarefa em código.

Diferenças em relação a outros tipos de coleção

A BlockingQueue fornece sincronização automatizada, gerenciando o acesso das threads à fila sem exigir sincronização manual. Também suporta operações de bloqueio para adicionar e recuperar itens, um recurso inexistente em outras coleções como ArrayList ou LinkedList.

Implementações de BlockingQueue

ArrayBlockingQueue: Uma fila limitada em tamanho que utiliza um array para armazenar os itens.

Main.java

Main.java

copy
123456789
// Constructor with fixed capacity BlockingQueue<String> queue1 = new ArrayBlockingQueue<>(5); // Constructor with fixed capacity and fair access BlockingQueue<String> queue2 = new ArrayBlockingQueue<>(5, true); // Constructor with fixed capacity and initial collection of elements Collection<String> initialElements = java.util.Arrays.asList("One", "Two", "Three"); BlockingQueue<String> queue3 = new ArrayBlockingQueue<>(5, false, initialElements);
Note
Nota

O parâmetro true habilita uma política de acesso justa ao fornecer uma ordem FIFO para o acesso das threads.

LinkedBlockingQueueue: Uma fila baseada em nós encadeados que pode ser restrita ou irrestrita.

Main.java

Main.java

copy
123456789
// Constructor without capacity bounds BlockingQueue<String> queue1 = new LinkedBlockingQueue<>(); // Constructor with fixed capacity BlockingQueue<String> queue2 = new LinkedBlockingQueue<>(5); // Constructor with initial collection of elements Collection<String> initialElements = java.util.Arrays.asList("One", "Two", "Three"); BlockingQueue<String> queue3 = new LinkedBlockingQueue<>(initialElements);

PriorityBlockingQueue: Uma fila prioritária sem limite onde os elementos são recuperados de acordo com sua ordem natural ou conforme especificado por um comparador.

Main.java

Main.java

copy
12345678910111213
// Constructor without initial capacity (default is 11) BlockingQueue<Integer> queue1 = new PriorityBlockingQueue<>(); // Constructor with initial capacity BlockingQueue<Integer> queue2 = new PriorityBlockingQueue<>(5); // Constructor with initial capacity and comparator Comparator<Integer> comparator = Integer::compareTo; BlockingQueue<Integer> queue3 = new PriorityBlockingQueue<>(5, comparator); // Constructor with initial collection of elements Collection<Integer> initialElements = java.util.Arrays.asList(1, 3, 2); BlockingQueue<Integer> queue4 = new PriorityBlockingQueue<>(initialElements)

DelayQueue: Uma fila atrasada onde os itens só podem ser recuperados após o vencimento do seu tempo de atraso.

DelayedElement.java

DelayedElement.java

DelayQueueConstructors.java

DelayQueueConstructors.java

copy
123456789101112131415161718
class DelayedElement implements Delayed { private final long expirationTime; // The time when the element will be available public DelayedElement(long delay, TimeUnit unit) { this.expirationTime = System.currentTimeMillis() + unit.toMillis(delay); } @Override public long getDelay(TimeUnit unit) { long delay = expirationTime - System.currentTimeMillis(); // Calculate the remaining delay return unit.convert(delay, TimeUnit.MILLISECONDS); // Convert the delay to the specified time unit } @Override public int compareTo(Delayed o) { return Long.compare(this.expirationTime, ((DelayedElement) o).expirationTime); } }

Este código demonstra o uso da classe DelayedElement, que implementa a interface Delayed, e da fila de atraso DelayQueue em Java. A classe DelayedElement define um método getDelay para calcular o tempo de atraso restante e um método compareTo para comparar objetos com base no tempo de expiração do atraso.

O método main cria duas filas: queue1, uma fila de atraso vazia, e queue2, uma fila inicializada com elementos que possuem atraso de 5 e 1 segundo, respectivamente.

Os itens em DelayQueueue tornam-se disponíveis para recuperação após o tempo de atraso especificado ter decorrido.

SynchronousQueueue: Uma fila sem capacidade, onde cada operação de inserção deve aguardar a correspondente operação de extração e vice-versa.

Main.java

Main.java

copy
12345
// Constructor without fair access BlockingQueue<String> queue1 = new SynchronousQueue<>(); // Constructor with fair access BlockingQueue<String> queue2 = new SynchronousQueue<>(true);

Principais métodos do BlockingQueue:

Adição de elementos:

O método void put(E e) insere um item na fila, bloqueando a thread se a fila estiver cheia. Alternativamente, o método boolean offer(E e, long timeout, TimeUnit unit) tenta adicionar um item à fila, aguardando pelo tempo especificado caso a fila esteja cheia.

Main.java

Main.java

copy
1234567891011121314151617
public class BlockingQueueExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { queue.put("Element 1"); // Insert the first element, no blocking. queue.put("Element 2"); // Insert the second element, no blocking. // Try to add the third element with a 2-second timeout. // Since the queue is full, it will wait for 2 seconds. boolean success = queue.offer("Element 3", 2, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } } }

Este exemplo demonstra a inserção de dois elementos em uma BlockingQueue sem bloqueio, seguida de uma tentativa de adicionar um terceiro elemento com um timeout de 2 segundos usando o método offer(), que aguardará caso a fila esteja cheia.

Recuperação de Elementos:

O método E take() recupera e retorna um item da fila, bloqueando a thread caso a fila esteja vazia. Alternativamente, o método E poll(long timeout, TimeUnit unit) tenta recuperar um item da fila, aguardando pelo tempo especificado caso a fila esteja vazia.

Main.java

Main.java

copy
1234567891011121314151617181920212223
public class BlockingQueueRetrievalExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Retrieve and remove the first element, no blocking since the queue is not empty String item1 = queue.take(); // Returns "Element 1" // Attempt to retrieve and remove the next element with a 2-second timeout String item2 = queue.poll(2, TimeUnit.SECONDS); // Returns "Element 2" // Attempt to retrieve an element when the queue is empty, this will block for 2 seconds String item3 = queue.poll(2, TimeUnit.SECONDS); // Returns `null` after timeout } catch (InterruptedException e) { e.printStackTrace(); } } }

Este código adiciona dois elementos a uma BlockingQueue, recupera e remove o primeiro elemento imediatamente, tenta recuperar o próximo elemento com um timeout de 2 segundos e, por fim, tenta recuperar um elemento de uma fila vazia, o que resulta em null após o tempo limite.

Verificação e Remoção de Elementos:

O método boolean remove(Object o) remove o elemento especificado da fila, se estiver presente. Por outro lado, o método boolean contains(Object o) verifica se o elemento especificado está presente na fila sem removê-lo.

Main.java

Main.java

copy
1234567891011121314151617181920212223242526
public class BlockingQueueCheckRemoveExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Check if "Element 1" is in the queue, should return `true` boolean containsElement1 = queue.contains("Element 1"); // true // Remove "Element 1" from the queue, should return `true` boolean removedElement1 = queue.remove("Element 1"); // true // Check if "Element 1" is still in the queue, should return `false` boolean containsElement1AfterRemoval = queue.contains("Element 1"); // false // Try to remove an element that is not in the queue, should return `false` boolean removedElement3 = queue.remove("Element 3"); // false } catch (InterruptedException e) { e.printStackTrace(); } } }

Este código adiciona dois elementos a uma BlockingQueue, verifica a presença de "Element 1", remove-o, verifica novamente para confirmar sua remoção e então tenta remover um elemento inexistente.

Consulta o Estado da Fila:

O método int size() retorna o número de elementos atualmente na fila. Para determinar se a fila está vazia, pode-se utilizar o método boolean isEmpty(), que verifica se a fila não possui elementos. Para filas com capacidade fixa, o método int remainingCapacity() fornece o número de espaços restantes disponíveis na fila.

Main.java

Main.java

copy
123456789101112131415161718192021222324252627282930
public class BlockingQueueCapacityExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(3); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Get the number of elements in the queue int currentSize = queue.size(); // 2 // Check if the queue is empty boolean isQueueEmpty = queue.isEmpty(); // false // Get the remaining capacity in the queue int remainingSpace = queue.remainingCapacity(); // 1 // Add another element to fill the queue queue.put("Element 3"); // Check the size and remaining capacity after adding the third element currentSize = queue.size(); // 3 remainingSpace = queue.remainingCapacity(); // 0 } catch (InterruptedException e) { e.printStackTrace(); } } }

Este código adiciona elementos a uma BlockingQueue, verifica o tamanho atual, verifica se a fila está vazia e determina a capacidade restante, depois atualiza esses valores após preencher completamente a fila.

Realizando um Exemplo da Vida Real em Código

😭 Limitações

Uma limitação importante é o desempenho: devido às operações de bloqueio envolvidas, o desempenho pode ser reduzido em comparação com coleções não sincronizadas. Além disso, recursos podem se tornar uma preocupação, pois filas grandes exigem mais memória e tempo de CPU para lidar com os bloqueios e os processos de sincronização.

💪 Vantagens

Por outro lado, o sistema é seguro em multithread, oferecendo comunicação segura entre threads sem exigir gerenciamento manual de sincronização. Também simplifica o código ao evitar construções complexas de sincronização e bloqueio. Além disso, a flexibilidade das diferentes implementações de BlockingQueue permite que sejam adequadas para vários cenários de uso.

1. O que é uma BlockingQueue em Java?

2. Quais são os principais métodos do BlockingQueue que bloqueiam uma thread?

3. Para que serve o BlockingQueue em aplicações multithread?

question mark

O que é uma BlockingQueue em Java?

Select the correct answer

question mark

Quais são os principais métodos do BlockingQueue que bloqueiam uma thread?

Select the correct answer

question mark

Para que serve o BlockingQueue em aplicações multithread?

Select the correct answer

Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 2. Capítulo 3
some-alt