Ответ
Работа с потоками в Java осуществляется через класс Thread и интерфейс Runnable (или Callable). Современные подходы рекомендуют использование высокоуровневых API, таких как ExecutorService.
1. Создание и запуск потока
Способ 1: Наследование от Thread (не рекомендуется из-за ограничения наследования)
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread is running: " + Thread.currentThread().getName());
}
}
// Запуск
new MyThread().start();
Способ 2: Реализация Runnable (предпочтительнее)
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable is running: " + Thread.currentThread().getName());
}
}
// Запуск
Thread thread = new Thread(new MyRunnable());
thread.start();
2. Использование Executor Framework (Java 5+)
Этот фреймворк управляет пулом потоков, избавляя от ручного создания Thread.
import java.util.concurrent.*;
// Создание пула с фиксированным количеством потоков
ExecutorService executor = Executors.newFixedThreadPool(4);
// Задача без возвращаемого значения (Runnable)
executor.execute(() -> {
System.out.println("Async task executed by: " + Thread.currentThread().getName());
});
// Задача с возвращаемым значением (Callable)
Future<Integer> future = executor.submit(() -> {
Thread.sleep(1000);
return 42;
});
// Получение результата (блокирующий вызов)
try {
Integer result = future.get(); // Ждёт завершения задачи
System.out.println("Result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// Корректное завершение пула
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
3. Критические секции и синхронизация
Для предотвращения состояния гонки (race condition) используется синхронизация.
Синхронизированный метод:
public class Counter {
private int count = 0;
public synchronized void increment() { count++; } // Монитор — this
public synchronized int getCount() { return count; }
}
Синхронизированный блок:
public void addItem(List<String> list, String item) {
synchronized(list) { // Монитор — объект list
list.add(item);
}
}
4. Современные подходы (Java 8+)
- CompletableFuture: Для асинхронного программирования и комбинирования задач.
CompletableFuture.supplyAsync(() -> fetchDataFromAPI()) .thenApply(data -> processData(data)) .thenAccept(result -> System.out.println(result)) .exceptionally(ex -> { ex.printStackTrace(); return null; }); - Параллельные стримы (Parallel Streams): Для параллельной обработки коллекций.
List<Integer> numbers = List.of(1, 2, 3, 4, 5); int sum = numbers.parallelStream() .mapToInt(Integer::intValue) .sum();
Ключевые принципы:
- Не создавайте потоки вручную (
new Thread()) для каждой задачи, используйтеExecutorService. - Всегда обрабатывайте
InterruptedExceptionкорректно. - Для совместного доступа к изменяемым данным используйте потокобезопасные коллекции из
java.util.concurrent(например,ConcurrentHashMap,CopyOnWriteArrayList).