Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Вивчайте BlockingQueue та Її Реалізації | Синхронізовані Колекції
Багатопотоковість у Java

bookBlockingQueue та Її Реалізації

Основні реалізації BlockingQueue

Ми не будемо розглядати кожну реалізацію детально, оскільки це займе багато часу, і навряд чи вам знадобляться всі. Я розповім про загальні концепції та які конструктори вони мають.

Приклад з реального життя

Уявіть собі фабрику, де один потік, виробник, створює деталі, а інший потік, споживач, їх обробляє. Виробник поміщає деталі у чергу, а споживач дістає та обробляє їх з черги. Якщо у черзі закінчуються деталі, споживач чекає, поки виробник додасть нові. І навпаки, якщо черга заповнена, виробник чекає, поки споживач звільнить місце.

Note
Примітка

Трохи нижче ми реалізуємо це завдання у коді.

Відмінності від інших типів колекцій

BlockingQueue забезпечує автоматизовану синхронізацію, керуючи доступом потоків до черги без необхідності ручної синхронізації. Також підтримує блокуючі операції для додавання та отримання елементів — ця функція відсутня в інших колекціях, таких як ArrayList або LinkedList.

Реалізації BlockingQueue

ArrayBlockingQueue: Черга з обмеженим розміром, яка використовує масив для зберігання елементів.

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
Примітка

Параметр true активує політику справедливого доступу, забезпечуючи порядок доступу потоків за принципом FIFO.

LinkedBlockingQueueue: черга на основі зв'язаних вузлів, яка може бути обмеженою або необмеженою.

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: Необмежена пріоритетна черга, в якій елементи отримуються відповідно до їх природного порядку або згідно з компаратором.

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: Черга із затримкою, де елементи можна отримати лише після закінчення їхнього часу затримки.

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); } }

Цей код демонструє використання класу DelayedElement, який реалізує інтерфейс Delayed, та черги із затримкою DelayQueue у Java. Клас DelayedElement визначає метод getDelay для обчислення залишкового часу затримки та метод compareTo для порівняння об'єктів за часом закінчення затримки.

Метод main створює дві черги: queue1порожню чергу із затримкою, та queue2 — чергу, ініціалізовану елементами із затримкою 5 та 1 секунда відповідно.

Елементи у DelayQueueue стають доступними для отримання після закінчення вказаного часу затримки.

SynchronousQueueue: Черга без місткості, де кожна операція вставки повинна чекати відповідної операції вилучення і навпаки.

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);

Основні методи BlockingQueue:

Додавання елементів:

Метод void put(E e) вставляє елемент у чергу, блокуючи потік, якщо черга заповнена. Альтернативно, метод boolean offer(E e, long timeout, TimeUnit unit) намагається додати елемент у чергу, очікуючи вказаний час, якщо черга заповнена.

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(); } } }

Цей приклад демонструє вставку двох елементів у BlockingQueue без блокування, після чого здійснюється спроба додати третій елемент з тайм-аутом 2 секунди за допомогою методу offer(), який чекатиме, якщо черга заповнена.

Отримання елементів:

Метод E take() отримує та повертає елемент з черги, блокуючи потік, якщо черга порожня. Альтернативно, метод E poll(long timeout, TimeUnit unit) намагається отримати елемент з черги, очікуючи вказаний час, якщо черга порожня.

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(); } } }

Цей код додає два елементи до BlockingQueue, отримує та видаляє перший елемент негайно, намагається отримати наступний елемент із тайм-аутом 2 секунди, а потім намагається отримати елемент з порожньої черги, що призводить до повернення null після закінчення тайм-ауту.

Перевірка та видалення елементів:

Метод boolean remove(Object o) видаляє зазначений елемент з черги, якщо він присутній. Натомість, метод boolean contains(Object o) перевіряє, чи присутній зазначений елемент у черзі, не видаляючи його.

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(); } } }

Цей код додає два елементи до BlockingQueue, перевіряє наявність "Element 1", видаляє його, знову перевіряє для підтвердження видалення, а потім намагається видалити неіснуючий елемент.

Опитування стану черги:

Метод int size() повертає кількість елементів, які наразі знаходяться в черзі. Щоб визначити, чи черга порожня, можна використати метод boolean isEmpty(), який перевіряє, чи немає елементів у черзі. Для черг із фіксованою місткістю метод int remainingCapacity() надає кількість доступних місць у черзі.

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(); } } }

Цей код додає елементи до BlockingQueue, перевіряє поточний розмір, визначає, чи є черга порожньою, а також визначає залишкову місткість, після чого оновлює ці значення після повного заповнення черги.

Реалізація реального прикладу в коді

😭 Обмеження

Одним із ключових обмежень є продуктивність: через операції блокування продуктивність може бути нижчою порівняно з несинхронізованими колекціями. Крім того, ресурси можуть стати проблемою, оскільки великі черги вимагають більше пам'яті та часу процесора для обробки блокувань і процесів синхронізації.

💪 Переваги

З позитивного боку, система є безпечна для багатопотокового середовища, забезпечуючи безпечну взаємодію між потоками без необхідності ручного керування синхронізацією. Вона також спрощує код, уникаючи складних конструкцій синхронізації та блокування. Крім того, гнучкість різних реалізацій BlockingQueue дозволяє використовувати їх у різних сценаріях.

1. Що таке BlockingQueue в Java?

2. Які основні методи BlockingQueue блокують потік?

3. Для чого корисний BlockingQueue у багатопотокових застосунках?

question mark

Що таке BlockingQueue в Java?

Select the correct answer

question mark

Які основні методи BlockingQueue блокують потік?

Select the correct answer

question mark

Для чого корисний BlockingQueue у багатопотокових застосунках?

Select the correct answer

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 2. Розділ 3

Запитати АІ

expand

Запитати АІ

ChatGPT

Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат

Awesome!

Completion rate improved to 3.33

bookBlockingQueue та Її Реалізації

Свайпніть щоб показати меню

Основні реалізації BlockingQueue

Ми не будемо розглядати кожну реалізацію детально, оскільки це займе багато часу, і навряд чи вам знадобляться всі. Я розповім про загальні концепції та які конструктори вони мають.

Приклад з реального життя

Уявіть собі фабрику, де один потік, виробник, створює деталі, а інший потік, споживач, їх обробляє. Виробник поміщає деталі у чергу, а споживач дістає та обробляє їх з черги. Якщо у черзі закінчуються деталі, споживач чекає, поки виробник додасть нові. І навпаки, якщо черга заповнена, виробник чекає, поки споживач звільнить місце.

Note
Примітка

Трохи нижче ми реалізуємо це завдання у коді.

Відмінності від інших типів колекцій

BlockingQueue забезпечує автоматизовану синхронізацію, керуючи доступом потоків до черги без необхідності ручної синхронізації. Також підтримує блокуючі операції для додавання та отримання елементів — ця функція відсутня в інших колекціях, таких як ArrayList або LinkedList.

Реалізації BlockingQueue

ArrayBlockingQueue: Черга з обмеженим розміром, яка використовує масив для зберігання елементів.

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
Примітка

Параметр true активує політику справедливого доступу, забезпечуючи порядок доступу потоків за принципом FIFO.

LinkedBlockingQueueue: черга на основі зв'язаних вузлів, яка може бути обмеженою або необмеженою.

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: Необмежена пріоритетна черга, в якій елементи отримуються відповідно до їх природного порядку або згідно з компаратором.

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: Черга із затримкою, де елементи можна отримати лише після закінчення їхнього часу затримки.

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); } }

Цей код демонструє використання класу DelayedElement, який реалізує інтерфейс Delayed, та черги із затримкою DelayQueue у Java. Клас DelayedElement визначає метод getDelay для обчислення залишкового часу затримки та метод compareTo для порівняння об'єктів за часом закінчення затримки.

Метод main створює дві черги: queue1порожню чергу із затримкою, та queue2 — чергу, ініціалізовану елементами із затримкою 5 та 1 секунда відповідно.

Елементи у DelayQueueue стають доступними для отримання після закінчення вказаного часу затримки.

SynchronousQueueue: Черга без місткості, де кожна операція вставки повинна чекати відповідної операції вилучення і навпаки.

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);

Основні методи BlockingQueue:

Додавання елементів:

Метод void put(E e) вставляє елемент у чергу, блокуючи потік, якщо черга заповнена. Альтернативно, метод boolean offer(E e, long timeout, TimeUnit unit) намагається додати елемент у чергу, очікуючи вказаний час, якщо черга заповнена.

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(); } } }

Цей приклад демонструє вставку двох елементів у BlockingQueue без блокування, після чого здійснюється спроба додати третій елемент з тайм-аутом 2 секунди за допомогою методу offer(), який чекатиме, якщо черга заповнена.

Отримання елементів:

Метод E take() отримує та повертає елемент з черги, блокуючи потік, якщо черга порожня. Альтернативно, метод E poll(long timeout, TimeUnit unit) намагається отримати елемент з черги, очікуючи вказаний час, якщо черга порожня.

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(); } } }

Цей код додає два елементи до BlockingQueue, отримує та видаляє перший елемент негайно, намагається отримати наступний елемент із тайм-аутом 2 секунди, а потім намагається отримати елемент з порожньої черги, що призводить до повернення null після закінчення тайм-ауту.

Перевірка та видалення елементів:

Метод boolean remove(Object o) видаляє зазначений елемент з черги, якщо він присутній. Натомість, метод boolean contains(Object o) перевіряє, чи присутній зазначений елемент у черзі, не видаляючи його.

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(); } } }

Цей код додає два елементи до BlockingQueue, перевіряє наявність "Element 1", видаляє його, знову перевіряє для підтвердження видалення, а потім намагається видалити неіснуючий елемент.

Опитування стану черги:

Метод int size() повертає кількість елементів, які наразі знаходяться в черзі. Щоб визначити, чи черга порожня, можна використати метод boolean isEmpty(), який перевіряє, чи немає елементів у черзі. Для черг із фіксованою місткістю метод int remainingCapacity() надає кількість доступних місць у черзі.

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(); } } }

Цей код додає елементи до BlockingQueue, перевіряє поточний розмір, визначає, чи є черга порожньою, а також визначає залишкову місткість, після чого оновлює ці значення після повного заповнення черги.

Реалізація реального прикладу в коді

😭 Обмеження

Одним із ключових обмежень є продуктивність: через операції блокування продуктивність може бути нижчою порівняно з несинхронізованими колекціями. Крім того, ресурси можуть стати проблемою, оскільки великі черги вимагають більше пам'яті та часу процесора для обробки блокувань і процесів синхронізації.

💪 Переваги

З позитивного боку, система є безпечна для багатопотокового середовища, забезпечуючи безпечну взаємодію між потоками без необхідності ручного керування синхронізацією. Вона також спрощує код, уникаючи складних конструкцій синхронізації та блокування. Крім того, гнучкість різних реалізацій BlockingQueue дозволяє використовувати їх у різних сценаріях.

1. Що таке BlockingQueue в Java?

2. Які основні методи BlockingQueue блокують потік?

3. Для чого корисний BlockingQueue у багатопотокових застосунках?

question mark

Що таке BlockingQueue в Java?

Select the correct answer

question mark

Які основні методи BlockingQueue блокують потік?

Select the correct answer

question mark

Для чого корисний BlockingQueue у багатопотокових застосунках?

Select the correct answer

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 2. Розділ 3
some-alt