Обмін між потоками. Клас Exchanger, Phaser

Прокрутити вниз

Обмін між потоками. Клас Exchanger/Phaser – уроки java

Для взаємодії між потоками у Java є спеціальні класи з пакету `java.util.concurrent`, такі як `Exchanger` і `Phaser`, які полегшують процес комунікації між потоками та допомагають у синхронізації.

Клас Exchanger

`Exchanger` дозволяє двом потокам обмінюватися даними в строго визначеній точці синхронізації. Кожен потік викликає метод `exchange()`, передаючи дані для обміну. Після цього обидва потоки блокуються, поки один з них не передасть свої дані іншому.

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

  • Два потоки: Клас працює виключно для двох потоків, які зустрічаються для обміну даними.
  • Блокування: Обидва потоки блокуються, поки не викличуть метод `exchange()`. Якщо один потік викликає цей метод, він блокується до тих пір, поки інший не викличе його також.
  • Обмін даними: Після того, як обидва потоки викликали `exchange()`, вони обмінюються своїми даними.

Приклад використання Exchanger:

import java.util.concurrent.Exchanger;

public class Main {
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<>();

// Перший потік
Thread thread1 = new Thread(() -> {
try {
String data = “Дані від потоку 1”;
System.out.println(“Потік 1 відправляє: ” + data);
String receivedData = exchanger.exchange(data);
System.out.println(“Потік 1 отримав: ” + receivedData);
} catch (InterruptedException e) {
e.printStackTrace();
}
});

// Другий потік
Thread thread2 = new Thread(() -> {
try {
String data = “Дані від потоку 2”;
System.out.println(“Потік 2 відправляє: ” + data);
String receivedData = exchanger.exchange(data);
System.out.println(“Потік 2 отримав: ” + receivedData);
} catch (InterruptedException e) {
e.printStackTrace();
}
});

thread1.start();
thread2.start();
}
}

Виведення:

Потік 1 відправляє: Дані від потоку 1
Потік 2 відправляє: Дані від потоку 2
Потік 1 отримав: Дані від потоку 2
Потік 2 отримав: Дані від потоку 1

У цьому прикладі два потоки обмінюються повідомленнями через об’єкт `Exchanger`. Обидва потоки викликають метод `exchange()` і чекають, поки інший потік викличе його також, після чого відбувається обмін.

Клас Phaser

`Phaser` є більш гнучкою версією `CyclicBarrier` та `CountDownLatch` і дозволяє синхронізувати виконання декількох етапів (фаз) для групи потоків. Потоки можуть виконувати роботу в декілька фаз, і `Phaser` забезпечує, що всі учасники завершили поточну фазу, перш ніж перейти до наступної.

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

  • Фази: Потоки виконують певну роботу в кілька фаз. Після завершення однієї фази, Phaser не дозволяє переходити до наступної, поки всі потоки не завершать поточну.
  • Динамічне додавання/видалення учасників: Клас дозволяє додавати або видаляти учасників (потоки) в процесі виконання.
  • Метод `arriveAndAwaitAdvance()`: Потік повідомляє про завершення фази та чекає, поки всі інші учасники також завершать поточну фазу.

Приклад використання Phaser:

import java.util.concurrent.Phaser;

public class Main {
public static void main(String[] args) {
Phaser phaser = new Phaser(1); // Реєструємо “головний” потік

// Створюємо три потоки
for (int i = 1; i <= 3; i++) {
int threadNum = i;
phaser.register(); // Реєструємо кожен потік в фазері
new Thread(() -> {
System.out.println(“Потік ” + threadNum + ” починає першу фазу.”);
phaser.arriveAndAwaitAdvance(); // Завершує першу фазу і чекає інших

System.out.println(“Потік ” + threadNum + ” починає другу фазу.”);
phaser.arriveAndAwaitAdvance(); // Завершує другу фазу і чекає інших
}).start();
}

// Головний потік знімає свою реєстрацію і починає фазування
phaser.arriveAndDeregister();

// Очікування завершення всіх фаз
while (!phaser.isTerminated()) {
// Головний потік може робити щось інше
}

System.out.println(“Всі потоки завершили свої фази.”);
}
}

Виведення:

Потік 1 починає першу фазу.
Потік 2 починає першу фазу.
Потік 3 починає першу фазу.
Потік 1 починає другу фазу.
Потік 2 починає другу фазу.
Потік 3 починає другу фазу.
Всі потоки завершили свої фази.

У цьому прикладі три потоки синхронізуються у двох фазах. Кожен потік починає фазу, виконує деяку роботу, а потім викликає `arriveAndAwaitAdvance()`, щоб чекати, поки інші потоки завершать поточну фазу.

Основні методи класу Phaser:

  • `arrive()`: Потік повідомляє, що завершив фазу, але не чекає інших потоків.
  • `arriveAndAwaitAdvance()`: Потік повідомляє, що завершив фазу, і чекає, поки всі інші потоки завершать поточну фазу.
  • `arriveAndDeregister()`: Потік повідомляє, що завершив фазу та більше не бере участь у фазах.
  • `isTerminated()`: Перевіряє, чи завершені всі фази.

Висновок

  1. Exchanger дозволяє двом потокам обмінюватися даними в точно визначеній точці синхронізації. Це корисно для випадків, коли потоки залежать від результатів один одного.
  2. Phaser є інструментом для синхронізації багатоступеневих (фазових) завдань між кількома потоками. Це корисно для задач, що виконуються в кілька етапів, коли потоки повинні синхронізуватися після кожного етапу.

Обмін між потоками. Клас ExchangerКлас Phaser