← Назад к вопросам

Какую библиотеку используют для работы с многопоточностью?

2.0 Middle🔥 201 комментариев
#Коллекции#Многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Библиотеки и инструменты для многопоточности в Java

Для работы с многопоточностью в Java используется несколько встроенных пакетов и внешних библиотек. Правильный выбор инструмента зависит от задачи.

1. Встроенный пакет java.lang (базовые инструменты)

Thread - основной класс для создания потоков.

// Способ 1: Наследование от Thread
public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread is running");
        for (int i = 0; i < 5; i++) {
            System.out.println("Count: " + i);
            try {
                Thread.sleep(1000); // Задержка на 1 сек
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); // Запускаем поток
        
        try {
            thread.join(); // Ждём завершения потока
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

// Способ 2: Реализация Runnable (рекомендуется)
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Thread is running");
    }
}

Thread thread = new Thread(new MyRunnable());
thread.start();

// С Lambda (Java 8+)
Thread thread = new Thread(() -> {
    System.out.println("Thread with lambda");
});
thread.start();

Методы Thread:

  • start() - запустить поток
  • run() - работа, которую выполнит поток
  • join() - ждать завершения потока
  • sleep() - задержка
  • interrupt() - прервать поток
  • isAlive() - проверить, активен ли поток
  • getName(), setName() - имя потока
  • getPriority(), setPriority() - приоритет

2. java.util.concurrent (современный подход - РЕКОМЕНДУЕТСЯ)

Это основная библиотека для многопоточности в Java!

2.1. Executor Framework

Executor - позволяет управлять пулом потоков вместо создания потоков вручную.

import java.util.concurrent.*;

// Способ 1: Используем ExecutorService
ExecutorService executorService = Executors.newFixedThreadPool(3);

// Отправляем задачи
for (int i = 0; i < 10; i++) {
    final int taskId = i;
    executorService.execute(() -> {
        System.out.println("Task " + taskId + " running");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("Task " + taskId + " done");
    });
}

// Завершаем работу
executorService.shutdown();
try {
    // Ждём, пока все задачи завершятся (максимум 10 сек)
    if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
        executorService.shutdownNow(); // Принудительно завершить
    }
} catch (InterruptedException e) {
    executorService.shutdownNow();
}

Типы Executor'ов:

// Fixed Thread Pool (фиксированное количество потоков)
ExecutorService executor1 = Executors.newFixedThreadPool(5);

// Cached Thread Pool (растущий пул, переиспользует потоки)
ExecutorService executor2 = Executors.newCachedThreadPool();

// Single Thread Executor (один поток)
ExecutorService executor3 = Executors.newSingleThreadExecutor();

// Scheduled Executor (для периодических задач)
ScheduledExecutorService executor4 = Executors.newScheduledThreadPool(2);

// Virtual Threads (Java 19+ - легкие потоки)
ExecutorService executor5 = Executors.newVirtualThreadPerTaskExecutor();

// Fork-Join Pool (для параллельных вычислений)
ExecutorService executor6 = ForkJoinPool.commonPool();

2.2. Future и Callable

Future - представляет результат асинхронного вычисления.

ExecutorService executor = Executors.newFixedThreadPool(2);

// Callable возвращает результат
Callable<Integer> task = () -> {
    System.out.println("Computing...");
    Thread.sleep(2000);
    return 42; // Результат
};

// Отправляем task и получаем Future
Future<Integer> future = executor.submit(task);

// Работаем дальше
System.out.println("Doing other work");

// Ждём результат
try {
    Integer result = future.get(); // Блокируется, пока результат не готов
    System.out.println("Result: " + result);
    
    // С timeout
    Integer resultWithTimeout = future.get(5, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
    e.printStackTrace();
}

// Проверка статуса
if (future.isDone()) {
    System.out.println("Task completed");
}
if (future.isCancelled()) {
    System.out.println("Task was cancelled");
}

executor.shutdown();

2.3. CompletableFuture (Java 8+)

CompletableFuture - асинхронная обработка с callback'ами (рекомендуется для современного кода).

// Создаём асинхронную задачу
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    System.out.println("Task 1: Computing...");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    return "Result from task 1";
});

// Цепуем операции
future.thenAccept(result -> {
    System.out.println("Task 2: Got " + result);
}).thenRun(() -> {
    System.out.println("Task 3: All done");
});

// Обработка ошибок
future.exceptionally(ex -> {
    System.out.println("Error: " + ex.getMessage());
    return "Default result";
});

// Композиция
CompletableFuture<String> combined = future
    .thenApply(result -> result.toUpperCase())
    .thenApply(result -> "Processed: " + result);

System.out.println(combined.join()); // Ждём результат

Основные методы:

  • supplyAsync() - создать асинхронную задачу, которая возвращает результат
  • runAsync() - создать асинхронную задачу без результата
  • thenAccept() - обработать результат
  • thenApply() - преобразовать результат
  • thenRun() - выполнить действие после
  • exceptionally() - обработать ошибку
  • join() - ждать результат
  • get() - ждать результат (с exception)

2.4. Synхронизаторы

Пакет java.util.concurrent содержит набор синхронизаторов:

// CountDownLatch - один ждёт, пока другие выполнят
CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
    executorService.execute(() -> {
        System.out.println("Worker: doing work");
        latch.countDown(); // Декрементируем счётчик
    });
}
latch.await(); // Ждём, пока счётчик станет 0
System.out.println("All workers done");

// CyclicBarrier - все ждут друг друга
CyclicBarrier barrier = new CyclicBarrier(3);
for (int i = 0; i < 3; i++) {
    executorService.execute(() -> {
        try {
            System.out.println("Worker: waiting at barrier");
            barrier.await(); // Ждём остальных
            System.out.println("Worker: continuing");
        } catch (BrokenBarrierException | InterruptedException e) {
            e.printStackTrace();
        }
    });
}

// Semaphore - ограничение ресурсов
Semaphore semaphore = new Semaphore(2);
for (int i = 0; i < 5; i++) {
    executorService.execute(() -> {
        try {
            semaphore.acquire(); // Берём позволение
            System.out.println("Accessing resource");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release(); // Отдаём позволение
        }
    });
}

2.5. BlockingQueue

BlockingQueue - потокобезопасная очередь для обмена данными.

BlockingQueue<String> queue = new LinkedBlockingQueue<>();

// Производитель
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(() -> {
    try {
        for (int i = 0; i < 5; i++) {
            queue.put("Item " + i); // Блокируется, если переполнена
            System.out.println("Produced: Item " + i);
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
});

// Потребитель
executor.execute(() -> {
    try {
        for (int i = 0; i < 5; i++) {
            String item = queue.take(); // Блокируется, если пуста
            System.out.println("Consumed: " + item);
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
});

executor.shutdown();

3. Внешние библиотеки

3.1. Vert.x (Event-driven асинхронность)

<dependency>
    <groupId>io.vertx</groupId>
    <artifactId>vertx-core</artifactId>
    <version>4.4.0</version>
</dependency>
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new MyVerticle(), result -> {
    if (result.succeeded()) {
        System.out.println("Verticle deployed");
    }
});

3.2. Project Reactor (Reactive programming)

<dependency>
    <groupId>io.projectreactor</groupId>
    <artifactId>reactor-core</artifactId>
    <version>2022.0.0</version>
</dependency>
Mono.fromCallable(() -> {
    return "Hello from Mono";
}).subscribe(System.out::println);

3.3. RxJava (Reactive extensions)

<dependency>
    <groupId>io.reactivex.rxjava3</groupId>
    <artifactId>rxjava</artifactId>
    <version>3.1.5</version>
</dependency>
Observable.create(emitter -> {
    emitter.onNext("Hello");
    emitter.onNext("World");
    emitter.onComplete();
}).subscribe(System.out::println);

Сравнение подходов

ПодходКогда использоватьСложность
Thread + synchronizedИзбегать!Высокая
java.util.concurrentБольшинство задачСредняя
ExecutorServiceРабота с пулом потоковНизкая
CompletableFutureАсинхронные операцииСредняя
Vert.xEvent-driven системыВысокая
Reactive (Reactor, RxJava)Потоки данныхВысокая
Virtual Threads (Java 19+)Простая асинхронностьНизкая

Лучшие практики

  1. Используй java.util.concurrent - никогда не создавай потоки вручную
  2. ExecutorService для пула потоков - это основной инструмент
  3. CompletableFuture для асинхронности - вместо callback'ов
  4. BlockingQueue для обмена данными - между потоками
  5. Избегай synchronized - используй ConcurrentHashMap, CopyOnWriteArrayList
  6. Virtual Threads (Java 19+) - если нужна максимальная простота
  7. Тестируй многопоточность - используй инструменты типа ThreadWeaver

Рекомендация

Для большинства Java приложений используй:

  1. ExecutorService из java.util.concurrent
  2. CompletableFuture для асинхронных операций
  3. BlockingQueue для обмена между потоками
  4. Избегай низкоуровневых инструментов (Thread, synchronized)

Заключение

Главная библиотека для многопоточности в Java - это java.util.concurrent. Она содержит всё необходимое: ExecutorService для управления потоками, CompletableFuture для асинхронности, и множество синхронизаторов. Для специальных случаев существуют внешние библиотеки (Vert.x, Reactor, RxJava), но в 95% случаев хватает встроенных инструментов.