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

Как был реализован Transaction lock

2.0 Middle🔥 191 комментариев
#Базы данных и SQL

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

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

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

# Реализация Transaction lock в Java

Определение и назначение

Transaction lock — это механизм синхронизации, который используется для контроля доступа к общим ресурсам в многопоточной среде. Он обеспечивает, что только один поток может получить доступ к критической секции кода в один момент времени, предотвращая race conditions и обеспечивая безопасность данных.

Основные типы locks в Java

1. Intrinsic Lock (монитор объекта)

Это встроенная в каждый объект Java механизм синхронизации:

public class Counter {
    private int value = 0;

    // synchronized метод — использует intrinsic lock
    public synchronized void increment() {
        value++;
    }

    public synchronized int getValue() {
        return value;
    }
}

Когда поток входит в synchronized метод, он автоматически получает монитор объекта (intrinsic lock). Другие потоки блокируются до освобождения монитора.

2. synchronized блок

public class BankAccount {
    private double balance = 1000;

    public void withdraw(double amount) {
        // Только этот блок защищён
        synchronized(this) {
            if (balance >= amount) {
                balance -= amount;
            }
        }
    }

    public void deposit(double amount) {
        synchronized(this) {
            balance += amount;
        }
    }
}

Реализация через явные блокировки (java.util.concurrent.locks)

ReentrantLock

import java.util.concurrent.locks.ReentrantLock;

public class ThreadSafeCounter {
    private int value = 0;
    private final ReentrantLock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            value++;
        } finally {
            lock.unlock();
        }
    }

    public int getValue() {
        lock.lock();
        try {
            return value;
        } finally {
            lock.unlock();
        }
    }
}

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

  • Один поток может несколько раз захватить один и тот же lock
  • Поддерживает условные переменные (Condition)
  • Возможность попытаться захватить lock с таймаутом

ReadWriteLock

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class CachedData {
    private String data = "initial";
    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    // Несколько потоков могут читать одновременно
    public String read() {
        lock.readLock().lock();
        try {
            return data;
        } finally {
            lock.readLock().unlock();
        }
    }

    // Только один поток может писать
    public void write(String newData) {
        lock.writeLock().lock();
        try {
            data = newData;
        } finally {
            lock.writeLock().unlock();
        }
    }
}

Условные переменные (Condition)

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ProducerConsumer {
    private int buffer = 0;
    private boolean isEmpty = true;
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notEmpty = lock.newCondition();
    private final Condition notFull = lock.newCondition();

    public void produce(int value) throws InterruptedException {
        lock.lock();
        try {
            while (!isEmpty) {
                notFull.await();  // Ждём, пока буфер будет пуст
            }
            buffer = value;
            isEmpty = false;
            notEmpty.signalAll();  // Уведомляем потребителей
        } finally {
            lock.unlock();
        }
    }

    public int consume() throws InterruptedException {
        lock.lock();
        try {
            while (isEmpty) {
                notEmpty.await();  // Ждём, пока данные появятся
            }
            int value = buffer;
            isEmpty = true;
            notFull.signalAll();  // Уведомляем производителей
            return value;
        } finally {
            lock.unlock();
        }
    }
}

Semaphore (семафор)

import java.util.concurrent.Semaphore;

public class PooledResource {
    private final Semaphore semaphore;
    private final int poolSize;

    public PooledResource(int poolSize) {
        this.poolSize = poolSize;
        this.semaphore = new Semaphore(poolSize);
    }

    public void acquire() throws InterruptedException {
        semaphore.acquire();  // Ждёт, пока будет доступен ресурс
    }

    public void release() {
        semaphore.release();  // Освобождает ресурс для других потоков
    }
}

StampedLock (Java 8+)

import java.util.concurrent.locks.StampedLock;

public class OptimizedCache {
    private String data = "initial";
    private final StampedLock lock = new StampedLock();

    public String readOptimistic() {
        long stamp = lock.tryOptimisticRead();  // Оптимистичное чтение
        String result = data;
        if (!lock.validate(stamp)) {
            // Данные изменились, переполучаем с полной блокировкой
            stamp = lock.readLock();
            try {
                result = data;
            } finally {
                lock.unlockRead(stamp);
            }
        }
        return result;
    }

    public void write(String newData) {
        long stamp = lock.writeLock();
        try {
            data = newData;
        } finally {
            lock.unlockWrite(stamp);
        }
    }
}

Блокировки в БД (Database Locks)

В контексте транзакций БД используются разные типы блокировок:

-- Shared Lock (читает несколько потоков)
SELECT * FROM users WHERE id = 1 LOCK IN SHARE MODE;

-- Exclusive Lock (пишет один поток)
SELECT * FROM users WHERE id = 1 FOR UPDATE;

Сравнение подходов

МеханизмПреимуществаНедостатки
synchronizedПростота, встроенныйОграниченная функциональность
ReentrantLockГибкость, условные переменныеЧуть сложнее в использовании
ReadWriteLockОптимизация для read-heavyOverhead при частых writes
StampedLockВысокая производительностьСложнее в использовании
SemaphoreКонтроль ресурсовНе для простой синхронизации

Best Practices

  1. Всегда используй try-finally при работе с явными locks
  2. Избегай вложенных блокировок — высокий риск deadlock
  3. Используй наиболее подходящий тип — ReadWriteLock для read-heavy сценариев
  4. Минимизируй критическую секцию — держи lock только столько, сколько необходимо
  5. Для простых случаев используй synchronized — меньше кода, лучше читаемость

Понимание транзакционных блокировок — ключевой навык для разработки многопоточных Java приложений.

Как был реализован Transaction lock | PrepBro