Класс ReentrantLock
Класс ReentrantLock представляет собой реализацию интерфейса Lock
и обеспечивает взаимное исключение потоков. В отличие от ключевого слова
synchronized, он даёт больше гибкости: позволяет опрашивать состояние
блокировки, ожидать её с таймаутом, прерывать ожидание, а также разделять
блокировки на справедливые и несправедливые. Конструктор без параметров
создаёт несправедливую блокировку, а конструктор с параметром boolean
(в первый параметр передаём true) - справедливую. Повторный вход
означает, что поток, уже удерживающий блокировку, может захватить её
повторно, и она должна быть освобождена столько же раз.
Синтаксис
ReentrantLock lock = new ReentrantLock();
ReentrantLock lock = new ReentrantLock(true);
Пример
Давайте защитим общий счётчик с помощью ReentrantLock.
Каждый поток захватывает блокировку методом lock,
увеличивает значение и освобождает блокировку методом unlock:
import java.util.concurrent.locks.ReentrantLock;
public class Main
{
private static int counter = 0;
private static final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException
{
Runnable task = () -> {
lock.lock();
try
{
counter++;
}
finally
{
lock.unlock();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(counter);
}
}
Результат выполнения кода:
2
Пример
Давайте продемонстрируем повторный вход: поток дважды захватывает одну и ту же блокировку, а затем дважды её освобождает:
import java.util.concurrent.locks.ReentrantLock;
public class Main
{
public static void main(String[] args)
{
ReentrantLock lock = new ReentrantLock();
lock.lock();
lock.lock();
System.out.println(lock.getHoldCount());
lock.unlock();
lock.unlock();
System.out.println(lock.getHoldCount());
}
}
Результат выполнения кода:
2
0