Какие классы использовал в синхронизации потоков
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Классы синхронизации потоков в 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* для производительности.