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

Какие классы использовал в синхронизации потоков

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

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

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

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

Классы синхронизации потоков в Java

Синхронизация — это механизм управления доступом нескольких потоков к общим ресурсам. Java предоставляет множество классов и примитивов для этого:

1. synchronized — встроенный примитив

Основной механизм синхронизации, основанный на мониторах:

public class Counter {
    private int count = 0;
    
    // Синхронизированный метод
    public synchronized void increment() {
        count++;
    }
    
    // Синхронизированный блок
    public void incrementBlock() {
        synchronized(this) {
            count++;
        }
    }
}

Удобно, но не гибко. Нельзя отпустить блокировку с тайм-аутом или проверить, занята ли она.

2. Lock (ReentrantLock)

ReentrantLock — более гибкая альтернатива synchronized, часть java.util.concurrent.locks:

public class Counter {
    private final Lock lock = new ReentrantLock();
    private int count = 0;
    
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
    
    public void incrementWithTimeout() throws InterruptedException {
        if (lock.tryLock(1, TimeUnit.SECONDS)) {
            try {
                count++;
            } finally {
                lock.unlock();
            }
        } else {
            System.out.println("Could not acquire lock");
        }
    }
}

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

  • lock() — блокировка (может привести к deadlock)
  • unlock() — разблокировка
  • tryLock() — неблокирующая попытка
  • tryLock(timeout) — попытка с тайм-аутом
  • lockInterruptibly() — можно прервать

3. ReadWriteLock

Позволяет множеству потоков читать одновременно, но только один поток может писать:

public class Cache<K, V> {
    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private Map<K, V> data = new HashMap<>();
    
    public V get(K key) {
        lock.readLock().lock();
        try {
            return data.get(key);
        } finally {
            lock.readLock().unlock();
        }
    }
    
    public void put(K key, V value) {
        lock.writeLock().lock();
        try {
            data.put(key, value);
        } finally {
            lock.writeLock().unlock();
        }
    }
}

Отлично для сценариев с частыми чтениями и редкими записями.

4. Semaphore

Семафор контролирует доступ к ресурсу ограниченным числом потоков:

public class ConnectionPool {
    private final Semaphore semaphore = new Semaphore(10); // 10 одновременных подключений
    private Queue<Connection> connections = new LinkedList<>();
    
    public Connection acquireConnection() throws InterruptedException {
        semaphore.acquire();
        return connections.poll();
    }
    
    public void releaseConnection(Connection conn) {
        connections.offer(conn);
        semaphore.release();
    }
}

Использование:

  • Ограничение числа потоков в пуле
  • Управление ресурсами БД
  • Rate limiting

5. CountDownLatch

Ожидание завершения N операций:

public class DataLoader {
    public void loadDataParallel(List<File> files) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(files.size());
        
        for (File file : files) {
            executor.submit(() -> {
                try {
                    loadFile(file);
                } finally {
                    latch.countDown();
                }
            });
        }
        
        latch.await(); // Ждём завершения всех файлов
        System.out.println("All files loaded");
    }
}

Особенности:

  • Одноразовое использование
  • Не сбрасывается после достижения нуля
  • Thread-safe

6. CyclicBarrier

Барьер для синхронизации группы потоков в одной точке:

public class MatrixMultiplication {
    private final int numThreads = 4;
    private final CyclicBarrier barrier = new CyclicBarrier(numThreads, 
        () -> System.out.println("Row computed, merging..."));
    
    public void computeParallel(Matrix a, Matrix b, Matrix result) {
        for (int i = 0; i < numThreads; i++) {
            int rowStart = i * (a.rows() / numThreads);
            int rowEnd = (i + 1) * (a.rows() / numThreads);
            
            executor.submit(() -> {
                computeRows(a, b, result, rowStart, rowEnd);
                try {
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }
    }
}

Отличается от CountDownLatch возможностью переиспользования.

7. Phaser

Универсальный синхронизатор для многофазных операций:

public class GameSimulation {
    private final Phaser phaser = new Phaser(4); // 4 игрока
    
    public void playGame() {
        for (int i = 0; i < 4; i++) {
            executor.submit(() -> {
                phaser.arriveAndAwaitAdvance(); // Ждём всех игроков
                System.out.println("Round 1 started");
                
                phaser.arriveAndAwaitAdvance(); // Ждём конца раунда
                System.out.println("Round 1 finished");
            });
        }
    }
}

8. AtomicInteger, AtomicReference

Атомарные переменные для безопасных операций без явной синхронизации:

public class Counter {
    private final AtomicInteger count = new AtomicInteger(0);
    
    public void increment() {
        count.incrementAndGet();
    }
    
    public int getAndReset() {
        return count.getAndSet(0);
    }
    
    public boolean compareAndSwap(int expected, int newValue) {
        return count.compareAndSet(expected, newValue);
    }
}

Методы:

  • get() / set() — безопасное получение/установка
  • incrementAndGet() — атомарное увеличение
  • compareAndSet() — Compare-And-Swap (CAS) операция
  • getAndSet() — получить и установить

9. Collections.synchronizedMap(), synchronizedList()

Синхронизированные обёртки для коллекций:

Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<>());
List<String> syncList = Collections.synchronizedList(new ArrayList<>());

// Но лучше использовать ConcurrentHashMap!
Map<String, String> concurrentMap = new ConcurrentHashMap<>();

10. ConcurrentHashMap

ConcurrentHashMap — высокопроизводительная альтернатива synchronized HashMap:

public class UserCache {
    private final ConcurrentHashMap<String, User> cache = new ConcurrentHashMap<>();
    
    public User getOrCompute(String id) {
        return cache.computeIfAbsent(id, key -> fetchFromDatabase(key));
    }
    
    public void updateUser(String id, User user) {
        cache.put(id, user);
    }
}

Преимущества:

  • Не блокирует всю карту, только сегмент
  • Итерация без снимка (ConcurrentModificationException реже)
  • Методы вроде computeIfAbsent() атомарны

Сравнение синхронизации

КлассИспользованиеПроизводительность
synchronizedПростые случаиНизкая
ReentrantLockГибкие требованияСредняя
AtomicIntegerСчётчикиВысокая
ConcurrentHashMapКэшированиеВысокая
SemaphoreОграничение ресурсовСредняя
CountDownLatchПараллельные операцииСредняя

Правило выбора: начните с synchronized для простоты, переходите на Lock/Concurrent* для производительности.