Повторно входящий замок в Java
Класс ReentrantLock реализует Lock и
считает, сколько раз один поток уже взял замок.
Поток может вызвать lock() повторно, не
заблокировав сам себя, пока не сделает столько же
unlock().
Такое поведение похоже на вложенные
synchronized методы одного объекта. Для
явного замка удобно вызывать getHoldCount()
и isHeldByCurrentThread() при отладке.
Два последовательных lock в одном потоке
и один unlock оставляют монитор занятым:
import java.util.concurrent.locks.ReentrantLock;
public class Main {
private static final ReentrantLock gate = new ReentrantLock();
static void nested() {
gate.lock();
try {
gate.lock();
try {
System.out.println(gate.getHoldCount());
} finally {
gate.unlock();
}
System.out.println(gate.getHoldCount());
} finally {
gate.unlock();
}
}
public static void main(String[] args) {
nested();
}
}
Практический пример: приватный метод уже под замком, а публичный снова входит в ту же защиту:
import java.util.concurrent.locks.ReentrantLock;
class Ledger {
private final ReentrantLock gate = new ReentrantLock();
private int balance = 0;
void add(int amount) {
gate.lock();
try {
balance += amount;
} finally {
gate.unlock();
}
}
void transferFrom(Ledger other, int amount) {
gate.lock();
try {
add(-amount);
other.add(amount);
} finally {
gate.unlock();
}
}
int read() {
gate.lock();
try {
return balance;
} finally {
gate.unlock();
}
}
}
Внутренний add снова берет тот же
ReentrantLock, и это безопасно. С
обычным нерentrant замком такой вызов привел бы
к взаимной блокировке.
ReentrantLock и поле level.
Метод push увеличивает уровень под
замком и вызывает pushAgain, который
тоже берет замок. После двух вложенных вызовов
уровень должен вырасти на 2.