Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Как обеспечить блокировку в Java
Блокировка (synchronization) — критический механизм для управления конкурентным доступом к ресурсам в многопоточных приложениях. Рассмотрим основные подходы:
1. Synchronized блоки
Синхронизация методов
public class Counter {
private int count = 0;
// Синхронизация всего метода
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
Синхронизация блока кода
public class Counter {
private int count = 0;
private Object lock = new Object();
public void increment() {
synchronized(lock) {
count++;
}
}
}
Блоки лучше методов, так как минимизируют время удержания блокировки.
2. ReentrantLock
Более гибкая альтернатива synchronized:
public class Counter {
private int count = 0;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
}
Преимущества ReentrantLock:
- Возможность lock со спецификацией timeout
- Условные переменные (Condition)
- Поддержка fair locks
public void incrementWithTimeout() throws InterruptedException {
if (lock.tryLock(5, TimeUnit.SECONDS)) {
try {
count++;
} finally {
lock.unlock();
}
}
}
3. AtomicInteger / AtomicReference
Для простых операций с примитивами используй atomic классы:
public class Counter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet(); // Без synchronized!
}
public int getCount() {
return count.get();
}
}
Compare-and-swap (CAS) операции:
AtomicInteger counter = new AtomicInteger(0);
boolean success = counter.compareAndSet(0, 1); // Если значение 0, установить 1
4. ReadWriteLock
Для сценариев с множеством читателей и редкими писателями:
public class Cache {
private ReadWriteLock lock = new ReentrantReadWriteLock();
private Map<String, String> data = new HashMap<>();
public String get(String key) {
lock.readLock().lock();
try {
return data.get(key);
} finally {
lock.readLock().unlock();
}
}
public void put(String key, String value) {
lock.writeLock().lock();
try {
data.put(key, value);
} finally {
lock.writeLock().unlock();
}
}
}
5. Volatile
Для простых флагов видимости между потоками:
public class ShutdownFlag {
private volatile boolean shutdown = false;
public void shutdown() {
shutdown = true; // Видимо всем потокам
}
public boolean isShutdown() {
return shutdown;
}
}
6. Semaphore
Для контроля доступа ограниченного числа потоков:
public class ConnectionPool {
private Semaphore semaphore = new Semaphore(10); // Максимум 10 соединений
public void useConnection() throws InterruptedException {
semaphore.acquire();
try {
// Работа с соединением
} finally {
semaphore.release();
}
}
}
7. Лучшие практики
Избегай deadlock:
// Плохо - риск deadlock
synchronized(lock1) {
synchronized(lock2) { }
}
// Хорошо - всегда один порядок
synchronized(lock1) {
synchronized(lock2) { }
}
Минимизируй время блокировки:
// Плохо
synchronized void expensiveOperation() {
doSomethingExpensive();
updateCounter();
}
// Хорошо
void expensiveOperation() {
doSomethingExpensive();
synchronized(lock) {
updateCounter();
}
}
Заключение
Выбирайте инструмент блокировки на основе требований: synchronized для простых случаев, ReentrantLock для сложной логики, Atomic для примитивов, volatile для флагов, ReadWriteLock для read-heavy сценариев.