LinkedBlockingQueue, отличия от других очередей.
LinkedBlockingQueue — это реализация блокирующей очереди на основе связанного списка, предоставляемая в пакете java.util.concurrent. Она поддерживает опциональную ограниченную емкость и используется для передачи данных между потоками с возможностью блокировки.
Основные отличия от других очередей:
Блокирующая очередь: Ожидает свободного места для добавления или доступного элемента для извлечения.
Основана на связанном списке: В отличие от ArrayBlockingQueue, которая использует массив, LinkedBlockingQueue использует связанный список.
Опциональная ограниченная емкость: Вы можете задать максимальную емкость очереди. По умолчанию емкость не ограничена.
Внутреннее устройство
LinkedBlockingQueue реализует блокирующую очередь с использованием двух внутренних объектов Node, а также использует механизмы блокировок для управления доступом к очереди.
Основные компоненты:
Внутренний класс Node:
Узел, содержащий данные и ссылку на следующий элемент в очереди.
Голова и хвост очереди:
head: Ссылка на первый узел в очереди.
last: Ссылка на последний узел в очереди.
Механизмы блокировки:
Две раздельные блокировки для вставки и удаления: putLock и takeLock.
Принцип работы:
Вставка элемента (put):
Захватывается блокировка putLock.
Проверяется, не превышает ли очередь максимальную емкость.
Создается новый узел и добавляется в конец очереди.
Если очередь была пустой, сигнализируется о наличии новых элементов (notEmpty.signal()).
Освобождается блокировка putLock.
Извлечение элемента (take):
Захватывается блокировка takeLock.
Проверяется, не пустая ли очередь.
Удаляется узел из начала очереди.
Если очередь была заполнена, сигнализируется о наличии свободного места (notFull.signal()).
Освобождается блокировка takeLock.
Ссылки на полезные статьи (спасибо авторам за проделанную работу) :
https://www.geeksforgeeks.org/linkedblockingqueue-class-in-java/
https://www.baeldung.com/java-queue-linkedblocking-concurrentlinked
#Java #Training #Medium #LinkedBlockingQueue
LinkedBlockingQueue — это реализация блокирующей очереди на основе связанного списка, предоставляемая в пакете java.util.concurrent. Она поддерживает опциональную ограниченную емкость и используется для передачи данных между потоками с возможностью блокировки.
Основные отличия от других очередей:
Блокирующая очередь: Ожидает свободного места для добавления или доступного элемента для извлечения.
Основана на связанном списке: В отличие от ArrayBlockingQueue, которая использует массив, LinkedBlockingQueue использует связанный список.
Опциональная ограниченная емкость: Вы можете задать максимальную емкость очереди. По умолчанию емкость не ограничена.
import java.util.concurrent.LinkedBlockingQueue;
public class LinkedBlockingQueueExample {
public static void main(String[] args) {
LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10);
try {
queue.put(1);
queue.put(2);
System.out.println(queue.take());
System.out.println(queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Внутреннее устройство
LinkedBlockingQueue реализует блокирующую очередь с использованием двух внутренних объектов Node, а также использует механизмы блокировок для управления доступом к очереди.
Основные компоненты:
Внутренний класс Node:
Узел, содержащий данные и ссылку на следующий элемент в очереди.
static class Node<E> {
E item;
Node<E> next;
Node(E x) { item = x; }
}
Голова и хвост очереди:
head: Ссылка на первый узел в очереди.
last: Ссылка на последний узел в очереди.
private transient Node<E> head;
private transient Node<E> last;
Механизмы блокировки:
Две раздельные блокировки для вставки и удаления: putLock и takeLock.
private final ReentrantLock putLock = new ReentrantLock();
private final Condition notFull = putLock.newCondition();
private final ReentrantLock takeLock = new ReentrantLock();
private final Condition notEmpty = takeLock.newCondition();
Принцип работы:
Вставка элемента (put):
Захватывается блокировка putLock.
Проверяется, не превышает ли очередь максимальную емкость.
Создается новый узел и добавляется в конец очереди.
Если очередь была пустой, сигнализируется о наличии новых элементов (notEmpty.signal()).
Освобождается блокировка putLock.
Извлечение элемента (take):
Захватывается блокировка takeLock.
Проверяется, не пустая ли очередь.
Удаляется узел из начала очереди.
Если очередь была заполнена, сигнализируется о наличии свободного места (notFull.signal()).
Освобождается блокировка takeLock.
import java.util.concurrent.LinkedBlockingQueue;
public class LinkedBlockingQueueExample {
public static void main(String[] args) {
LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(2);
// Вставка элементов
new Thread(() -> {
try {
queue.put(1);
System.out.println("Inserted 1");
queue.put(2);
System.out.println("Inserted 2");
queue.put(3);
System.out.println("Inserted 3");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
// Извлечение элементов
new Thread(() -> {
try {
Thread.sleep(2000);
System.out.println("Removed " + queue.take());
System.out.println("Removed " + queue.take());
System.out.println("Removed " + queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
Ссылки на полезные статьи (спасибо авторам за проделанную работу) :
https://www.geeksforgeeks.org/linkedblockingqueue-class-in-java/
https://www.baeldung.com/java-queue-linkedblocking-concurrentlinked
#Java #Training #Medium #LinkedBlockingQueue
GeeksforGeeks
LinkedBlockingQueue Class in Java - GeeksforGeeks
A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.
Основные методы LinkedBlockingQueue
put(E e):
Вставляет элемент в конец очереди. Если очередь заполнена, блокируется до освобождения места.
take():
Извлекает и удаляет элемент из начала очереди. Если очередь пуста, блокируется до появления элемента.
offer(E e):
Вставляет элемент в конец очереди, если есть свободное место. Возвращает true, если элемент был добавлен, иначе false.
poll():
Извлекает и удаляет элемент из начала очереди. Возвращает null, если очередь пуста.
peek():
Возвращает элемент из начала очереди без его удаления. Возвращает null, если очередь пуста.
remainingCapacity():
Возвращает количество свободных мест в очереди.
drainTo(Collection<? super E> c):
Перемещает все доступные элементы в указанную коллекцию.
clear():
Удаляет все элементы из очереди.
Примеры использования
Производитель-потребитель:
Очередь задач:
#Java #Training #Medium #LinkedBlockingQueue
put(E e):
Вставляет элемент в конец очереди. Если очередь заполнена, блокируется до освобождения места.
LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(2);
queue.put(1);
queue.put(2);
take():
Извлекает и удаляет элемент из начала очереди. Если очередь пуста, блокируется до появления элемента.
Integer item = queue.take();
System.out.println(item);
offer(E e):
Вставляет элемент в конец очереди, если есть свободное место. Возвращает true, если элемент был добавлен, иначе false.
boolean added = queue.offer(3);
System.out.println(added); // false, если очередь заполнена
poll():
Извлекает и удаляет элемент из начала очереди. Возвращает null, если очередь пуста.
Integer item = queue.poll();
System.out.println(item);
peek():
Возвращает элемент из начала очереди без его удаления. Возвращает null, если очередь пуста.
Integer item = queue.peek();
System.out.println(item);
remainingCapacity():
Возвращает количество свободных мест в очереди.
int capacity = queue.remainingCapacity();
System.out.println(capacity);
drainTo(Collection<? super E> c):
Перемещает все доступные элементы в указанную коллекцию.
List<Integer> list = new ArrayList<>();
queue.drainTo(list);
System.out.println(list);
clear():
Удаляет все элементы из очереди.
queue.clear();
Примеры использования
Производитель-потребитель:
import java.util.concurrent.LinkedBlockingQueue;
public class ProducerConsumerExample {
public static void main(String[] args) {
LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(5);
// Производитель
new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
queue.put(i);
System.out.println("Produced: " + i);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
// Потребитель
new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
Integer item = queue.take();
System.out.println("Consumed: " + item);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
}
Очередь задач:
import java.util.concurrent.LinkedBlockingQueue;
public class TaskQueueExample {
public static void main(String[] args) {
LinkedBlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>(10);
// Запуск потока исполнителя задач
new Thread(() -> {
while (true) {
try {
Runnable task = taskQueue.take();
task.run();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}).start();
// Добавление задач в очередь
taskQueue.offer(() -> System.out.println("Task 1 executed"));
taskQueue.offer(() -> System.out.println("Task 2 executed"));
}
}
#Java #Training #Medium #LinkedBlockingQueue