ReentrantLock
Явная блокировка — гибкая замена `synchronized`.
Доступно с: Java 1.5
Синтаксис
public class ReentrantLock implements LockПримеры
Обязательный unlock() в finally:
class Account {
private final ReentrantLock lock = new ReentrantLock();
private int balance = 100;
boolean withdraw(int amount) {
lock.lock();
try {
if (balance < amount) return false;
balance -= amount;
return true;
} finally {
lock.unlock();
}
}
int balance() { return balance; }
}
void main() throws InterruptedException {
var acc = new Account();
var ok = new AtomicInteger();
Runnable task = () -> { for (int i = 0; i < 10; i++) if (acc.withdraw(10)) ok.incrementAndGet(); };
Thread a = new Thread(task), b = new Thread(task);
a.start(); b.start();
a.join(); b.join();
IO.println(ok.get() + " withdrawals, balance " + acc.balance());
}Результат:
10 withdrawals, balance 0Примечания
Всегда вызывайте unlock() в finally, иначе после исключения блокировка останется навсегда. В отличие от synchronized, умеет ждать с таймаутом (tryLock(1, TimeUnit.SECONDS)), прерываться и работать в «честном» режиме. Если эти возможности не нужны, synchronized проще.
См. также
- synchronized — Разрешает выполнять блок кода только одному потоку за раз.
- AtomicInteger — Целое число, которое можно безопасно менять из нескольких потоков без блокировок.
В учебнике
- Синхронизация — Гонка данных в Java и как её избежать — synchronized-методы и блоки, атомарные классы AtomicInteger, ReentrantLock и общий объект блокировки.