Основы многопоточности
Многопоточность позволяет выполнять несколько задач одновременно. В Java потоки (threads) — это лёгкие процессоры, которые разделяют память процесса.
▸Создание потоков
1// Способ 1: наследование Thread2class MyThread extends Thread {3 @Override4 public void run() {5 System.out.println("Поток: " + Thread.currentThread().getName());6 }7}89// Способ 2: реализация Runnable10Runnable task = () -> {11 System.out.println("Задача выполняется");12};13new Thread(task).start();1415// Способ 3: Callable с возвращаемым значением16Callable<Integer> callable = () -> {17 return 42;18};19ExecutorService executor = Executors.newSingleThreadExecutor();20Future<Integer> future = executor.submit(callable);
Проблемы многопоточности
▸Гонка данных (Race Condition)
Когда два потока одновременно изменяют общую переменную:
1// Проблема: гонка данных2private int counter = 0;34public void increment() {5 counter++; // Не атомарная операция!6 // 1. Читает counter7 // 2. Прибавляет 18 // 3. Записывает результат9}
▸Мёртвая блокировка (Deadlock)
Два потока ждут освобождения ресурсов, заблокированных друг другом:
1// Поток 1:2synchronized (lockA) {3 synchronized (lockB) { /* ... */ }4}56// Поток 2:7synchronized (lockB) {8 synchronized (lockA) { /* ... */ } // Deadlock!9}
Синхронизация
▸synchronized
1public class Counter {2 private int count = 0;34 public synchronized void increment() {5 count++;6 }78 public synchronized int getCount() {9 return count;10 }11}1213// Блокировка на уровне объекта14public void updateSharedData() {15 synchronized (this) {16 // критическая секция17 }18}
▸Lock interface
1private final ReentrantLock lock = new ReentrantLock();2private final Condition notEmpty = lock.newCondition();34public void produce() {5 lock.lock();6 try {7 // производство данных8 notEmpty.signal();9 } finally {10 lock.unlock();11 }12}1314public void consume() throws InterruptedException {15 lock.lock();16 try {17 while (isEmpty()) {18 notEmpty.await();19 }20 // потребление данных21 } finally {22 lock.unlock();23 }24}
ExecutorService
▸Пулы потоков
1// Фиксированный пул2ExecutorService fixedPool = Executors.newFixedThreadPool(4);34// Пул с кэшированием5ExecutorService cachedPool = Executors.newCachedThreadPool();67// Пул сcheduled задач8ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(2);910// Отправка задач11fixedPool.submit(() -> {12 System.out.println("Выполняется в пуле потоков");13});1415// Shutdown16fixedPool.shutdown();17fixedPool.awaitTermination(60, TimeUnit.SECONDS);
CompletableFuture
▸Асинхронное программирование
1CompletableFuture.supplyAsync(() -> {2 return fetchDataFromService();3})4.thenApply(data -> {5 return transformData(data);6})7.thenAccept(result -> {8 saveResult(result);9})10.exceptionally(ex -> {11 log.error("Ошибка: {}", ex.getMessage());12 return null;13});
▸Комбинирование задач
1CompletableFuture<User> userFuture = getUserAsync();2CompletableFuture<List<Order>> ordersFuture = getOrdersAsync();34// Ждём оба результата5CompletableFuture<Void> combined = CompletableFuture.allOf(userFuture, ordersFuture);6combined.join();78User user = userFuture.join();9List<Order> orders = ordersFuture.join();
Атомарные операции
▸AtomicInteger, AtomicLong
1private AtomicInteger atomicCounter = new AtomicInteger(0);23public void increment() {4 atomicCounter.incrementAndGet();5}67public int get() {8 return atomicCounter.get();9}
▸ConcurrentHashMap
1ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();23// Атомарное обновление4map.compute("key", (k, v) -> v == null ? 1 : v + 1);56// Атомарное добавление если отсутствует7map.putIfAbsent("key", 1);
Вольтайлы и Happens-Before
▸volatile
1private volatile boolean running = true;23public void stop() {4 running = false; // Видимо другим потокам5}67public void run() {8 while (running) {9 // работа10 }11}
▸Happens-Before гарантии
Функциональные интерфейсы для параллелизма
1// parallelStream для параллельной обработки коллекций2List<Result> results = data.parallelStream()3 .filter(item -> item.isActive())4 .map(this::processItem)5 .collect(Collectors.toList());
Заключение
Многопоточность — одна из самых сложных и важных тем в Java. На собеседовании обязательно спросят о race conditions, deadlock, synchronized vs Lock, ExecutorService и CompletableFuture. Практикуйтесь с реальными сценариями параллельной обработки данных.