Пакет java.util.concurrent предоставляет несколько классов и конструкций, которые обеспечивают более детальный контроль над синхронизацией и предназначены для обработки расширенных сценариев параллелизма. Вот некоторые ключевые классы и конструкции, которые могут быть полезны:

  1. Lock Интерфейс: Интерфейс java.util.concurrent.locks.Lock обеспечивает более гибкую альтернативу внутренней блокировке (synchronized блоки/методы). Он обеспечивает явную блокировку и разблокировку, поддерживает различные стратегии блокировки и предоставляет дополнительные функции, такие как справедливость, прерываемое получение блокировки и попытки блокировки по времени. Наиболее часто используемая реализация — ReentrantLock.
  2. ReadWriteLock Интерфейс: Интерфейс java.util.concurrent.locks.ReadWriteLock позволяет различать блокировки чтения и записи. Это позволяет нескольким потокам одновременно читать общий ресурс, обеспечивая при этом монопольный доступ для записи. Класс ReentrantReadWriteLock является стандартной реализацией этого интерфейса.
  3. Класс Semaphore: Класс java.util.concurrent.Semaphore представляет собой примитив синхронизации, который позволяет контролировать доступ к ограниченному числу ресурсов. Он предоставляет определенное количество разрешений, которые могут быть получены и освобождены потоками. Семафоры полезны в сценариях, где вы хотите ограничить одновременный доступ к определенному количеству ресурсов.
  4. Класс CountDownLatch: Класс java.util.concurrent.CountDownLatch представляет собой средство синхронизации, которое позволяет одному или нескольким потокам ожидать завершения набора операций, выполняемых в других потоках. Он инициализируется счетчиком, и каждый вызов countDown() уменьшает счетчик. Потоки могут ждать, пока счетчик достигнет нуля, используя метод await().
  5. Класс CyclicBarrier: Класс java.util.concurrent.CyclicBarrier — это еще одно средство синхронизации, которое позволяет группе потоков ожидать у барьера, пока все потоки не достигнут его. После прибытия всех потоков выполняется указанное барьерное действие. CyclicBarrier может быть полезен в сценариях, где вы хотите синхронизировать ход выполнения нескольких потоков в определенные моменты.
  6. Executor Платформа: Платформа java.util.concurrent.Executor обеспечивает абстракцию более высокого уровня для управления и асинхронного выполнения задач в пуле потоков. Он предлагает различные реализации, такие как ThreadPoolExecutor, ScheduledThreadPoolExecutor, а также служебные классы, такие как Executors, для упрощения отправки и выполнения задач.
  7. Класс CompletableFuture: Класс java.util.concurrent.CompletableFuture предоставляет мощный способ обработки асинхронных вычислений и их компоновки неблокирующим способом. Он поддерживает связывание и объединение нескольких асинхронных операций, обработку исключений и выполнение обратных вызовов после завершения вычислений.

Теперь приведите пример для каждого из них

Интерфейс блокировки. В этом примере ReentrantLock используется для синхронизации доступа к критическому разделу кода (метод criticalSection()). Блокировка устанавливается с помощью lock.lock() и снимается с помощью lock.unlock().

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class SharedResource {
    private Lock lock = new ReentrantLock();

    public void criticalSection() {
        lock.lock();
        try {
            // Critical section code
        } finally {
            lock.unlock();
        }
    }
}

ReadWriteLock Интерфейс (с использованием ReentrantReadWriteLock):

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

class SharedResource {
    private ReadWriteLock lock = new ReentrantReadWriteLock();
    private int value;

    public int readValue() {
        lock.readLock().lock();
        try {
            return value;
        } finally {
            lock.readLock().unlock();
        }
    }

    public void writeValue(int newValue) {
        lock.writeLock().lock();
        try {
            value = newValue;
        } finally {
            lock.writeLock().unlock();
        }
    }
}

В этом примере ReentrantReadWriteLock используется для разрешения одновременного чтения (readValue()) и эксклюзивной записи (writeValue()) к общему ресурсу (value).

Semaphore Класс:

import java.util.concurrent.Semaphore;

class ResourcePool {
    private Semaphore semaphore;

    public ResourcePool(int maxResources) {
        semaphore = new Semaphore(maxResources);
    }

    public void useResource() throws InterruptedException {
        semaphore.acquire();
        try {
            // Use the resource
        } finally {
            semaphore.release();
        }
    }
}

В этом примере Semaphore используется для управления доступом к ограниченному количеству ресурсов (maxResources). Метод useResource() получает разрешение от семафора перед использованием ресурса и после этого освобождает его.

CountDownLatch Класс:

import java.util.concurrent.CountDownLatch;

class Worker implements Runnable {
    private CountDownLatch latch;

    public Worker(CountDownLatch latch) {
        this.latch = latch;
    }

    public void run() {
        // Perform work

        latch.countDown(); // Signal completion
    }
}

class Main {
    public static void main(String[] args) throws InterruptedException {
        int workerCount = 3;
        CountDownLatch latch = new CountDownLatch(workerCount);

        for (int i = 0; i < workerCount; i++) {
            Worker worker = new Worker(latch);
            Thread thread = new Thread(worker);
            thread.start();
        }

        latch.await(); // Wait for all workers to complete
        System.out.println("All workers have completed.");
    }
}

В этом примере CountDownLatch используется для координации нескольких рабочих потоков (класс Worker). Основной поток ожидает завершения всех рабочих процессов, вызывая latch.await(), а затем приступает к печати сообщения о завершении.

CyclicBarrier Класс:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

class Worker implements Runnable {
    private CyclicBarrier barrier;

    public Worker(CyclicBarrier barrier) {
        this.barrier = barrier;
    }

    public void run() {
        try {
            // Perform partial work

            barrier.await(); // Wait for other workers
            // Perform remaining work after synchronization
        } catch (InterruptedException | BrokenBarrierException e) {
            // Handle exceptions
        }
    }
}

class Main {
    public static void main(String[] args) {
        int workerCount = 3;
        CyclicBarrier barrier = new CyclicBarrier(workerCount, () -> {
            System.out.println("All workers have reached the barrier.");
        });

        for (int i = 0; i < workerCount; i++) {
            Worker worker = new Worker(barrier);
            Thread thread = new Thread(worker);
            thread.start();
        }
    }
}

В этом примере CyclicBarrier используется для синхронизации нескольких рабочих потоков (класс Worker). Каждый рабочий выполняет частичную работу, а затем ждет у шлагбаума, используя barrier.await(). Как только все работники достигают барьера, выполняется действие барьера и печатается сообщение.

Executor Framework (с использованием ThreadPoolExecutor):

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Task implements Runnable {
    private int taskId;

    public Task(int taskId) {
        this.taskId = taskId;
    }

    public void run() {
        System.out.println("Task " + taskId + " is executing.");
        // Perform the task logic
    }
}

class Main {
    public static void main(String[] args) {
        int threadPoolSize = 3;
        ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);

        for (int i = 0; i < 5; i++) {
            Task task = new Task(i);
            executor.execute(task);
        }

        executor.shutdown();
    }
}

В этом примере ThreadPoolExecutor из платформы Executor используется для управления пулом потоков фиксированного размера. Задачи, представленные классом Task, передаются исполнителю с помощью executor.execute(task) и выполняются одновременно доступными потоками в пуле.

CompletableFuture Класс :

import java.util.concurrent.CompletableFuture;

class Main {
    public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // Perform an asynchronous computation
            return "Result";
        });

        future.thenAccept(result -> {
            // Process the result when the computation completes
            System.out.println("Result: " + result);
        });

        future.exceptionally(ex -> {
            // Handle exceptions that occurred during the computation
            System.out.println("Exception: " + ex.getMessage());
            return null;
        });
    }
}

В этом примере CompletableFuture создается с использованием метода supplyAsync, который представляет собой асинхронное вычисление. Метод thenAccept определяет обратный вызов, который вызывается с результатом вычисления после его завершения. Метод exceptionally позволяет обрабатывать любые исключения, возникшие во время вычислений.

Эти примеры дают представление об использовании платформы Executor и класса CompletableFuture. Они предлагают абстракции более высокого уровня для управления параллельными задачами и обработки асинхронных вычислений более рациональным и эффективным способом.

Эти примеры иллюстрируют базовое использование каждой утилиты параллелизма. Вы можете модифицировать и адаптировать их, чтобы они соответствовали более сложным сценариям и требованиям ваших собственных приложений.