Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Write Head Lock в многопоточности и базах данных
Write Head Lock — это механизм синхронизации, используемый для управления конкурентным доступом к ресурсам (обычно файлам или данным в памяти) в многопоточной среде. Главная идея: разрешить одновременно несколько читателей, но только одного писателя, и не позволять читателям и писателям работать одновременно.
ReadWriteLock в Java
Это реализация паттерна write head lock в стандартной библиотеке Java:
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockExample {
private ReadWriteLock lock = new ReentrantReadWriteLock();
private int counter = 0;
// Метод для чтения
public int read() {
lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " читает: " + counter);
Thread.sleep(1000); // Имитация долгого чтения
return counter;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.readLock().unlock();
}
return -1;
}
// Метод для записи
public void write(int value) {
lock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " пишет: " + value);
Thread.sleep(1000); // Имитация долгой записи
counter = value;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.writeLock().unlock();
}
}
public static void main(String[] args) {
ReadWriteLockExample example = new ReadWriteLockExample();
// Несколько читателей могут работать одновременно
new Thread(() -> example.read(), "Reader-1").start();
new Thread(() -> example.read(), "Reader-2").start();
// Писатель будет ждать, пока читатели завершат работу
new Thread(() -> example.write(42), "Writer-1").start();
}
}
Сравнение: Synchronized vs ReadWriteLock
Synchronized (простой подход):
public synchronized int read() {
return counter; // Только один поток за раз
}
public synchronized void write(int value) {
counter = value; // Только один поток за раз
}
// Проблема: читатели блокируют друг друга, хотя это неопасно
ReadWriteLock (оптимизированный подход):
public int read() {
lock.readLock().lock();
try {
return counter; // Несколько читателей одновременно
} finally {
lock.readLock().unlock();
}
}
Write Head Lock в базах данных
PostgreSQL и MySQL используют write head lock для управления конфликтами:
// В JDBC с блокировкой на запись
Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost/mydb");
conn.setAutoCommit(false);
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
Statement stmt = conn.createStatement();
// SELECT FOR UPDATE блокирует выбранные строки от других писателей
stmt.execute("SELECT * FROM users WHERE id = 1 FOR UPDATE");
// Теперь никто другой не может обновить эту строку
stmt.execute("UPDATE users SET name = 'New Name' WHERE id = 1");
conn.commit();
conn.close();
Сценарий конфликта
Время | Reader-1 | Reader-2 | Writer-1 | counter
------|-------------|-------------|---------------|--------
0 | readLock() | | | 0
1 | | readLock() | | 0 (оба читают)
2 | | | writeLock() | 0 (ждёт)
3 | readUnlock()| readUnlock()| получит lock | 0
4 | | | write(42) | 42
5 | | | writeUnlock() | 42
Практический пример: кэш с read/write lock
public class CacheWithReadWriteLock<K, V> {
private final Map<K, V> cache = new HashMap<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public V get(K key) {
lock.readLock().lock();
try {
return cache.get(key); // Несколько потоков могут читать одновременно
} finally {
lock.readLock().unlock();
}
}
public void put(K key, V value) {
lock.writeLock().lock();
try {
cache.put(key, value); // Только один поток может писать
} finally {
lock.writeLock().unlock();
}
}
public void invalidate(K key) {
lock.writeLock().lock();
try {
cache.remove(key);
} finally {
lock.writeLock().unlock();
}
}
public static void main(String[] args) {
CacheWithReadWriteLock<String, String> cache = new CacheWithReadWriteLock<>();
cache.put("name", "John");
// Несколько читателей
for (int i = 0; i < 5; i++) {
new Thread(() -> {
System.out.println(cache.get("name"));
}).start();
}
// Один писатель
new Thread(() -> cache.put("name", "Jane")).start();
}
}
Когда использовать write head lock
- Частое чтение, редкая запись: кэши, конфигурация
- Высокая конкурентность чтения: многопользовательские системы
- Обновление коллекций: thread-safe вспомогательные структуры
Производительность
- ReadWriteLock медленнее, чем Synchronized, если мало читателей
- ReadWriteLock быстрее при много читателей, мало писателей (типичный кэш)
- Дополнительный overhead на управление двумя блокировками