предисловие
ReentrantLock предоставляет честные и нечестные блокировки, вам нужно использовать только одну из них в конструкторе.boolean
параметры. Несправедливая блокировка по умолчанию.
Сегодня давайте посмотрим на разницу и конкретную реализацию на уровне исходного кода.
1. UML-диаграмма класса
ReentrantLock
Внутри есть абстрактный классSync
, который наследует AQS.
И реализация честной блокировкиFairSync
, реализация несправедливой блокировкиNodFairSync
.
Разница между двумя замками в том, чтоlock
реализация метода.
2. Реализация метода блокировки Fair Lock
final void lock() {
acquire(1);
}
AQS называетсяacquire
метод, учащиеся, знакомые с AQS, знают, что AQS вызовет подклассtryAcquire
способ увидеть честный замокtryAcquire
выполнить.
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
Скажи логику:
- Получите переменную состояния, если она равна 0, блокировку можно получить.
- Определите, есть ли ожидающие потоки в очереди AQS., если нет, попробуйте получить его с помощью CAS. После успешного получения измените поток удержания CLH на текущий поток.
- Логика реентерабельной блокировки.
- В случае сбоя и возврата false AQS поставит поток в очередь и приостановит его.
Обратите внимание на второй шаг выше:Определите, есть ли ожидающие потоки в очереди AQS..
Это справедливость.
Посмотрите еще раз на разницу между несправедливыми блокировками.
3. Реализация метода блокировки недобросовестной блокировки
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
Метод блокировки отличается. Импульсный метод заключается в использовании CAS для получения блокировки напрямую. Если это удается, установить поток, удерживающий блокировку, на себя. очень быстро. Поэтому по умолчанию используются несправедливые блокировки.
Если это не удается, позвоните в AQSacquire
метод. Конечно, мы все еще смотрим наtryAcquire
метод в приведенном выше коде,tryAcquire
Метод вызывает родительский классSync
изnonfairTryAcquire
а почему в родительском классе?
существуетReentrantLock
изtryLock
метод, этот метод также называется. Потому что этот метод возвращает быстро. Этот метод не позволяет потокам, ожидающим в течение длительного времени, получить блокировку. соответствоватьtryLock
дизайн.
Метод реализуется следующим образом:
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
Этот метод является относительно честной блокировкойtryAcquire
метод, на один шаг меньшеОпределите, есть ли ожидающие потоки в очереди AQS.операция.
Все, что ему нужно сделать, это схватить замок напрямую и не позволять тем, кто стоит в очереди, долго ждать.
Не могу снова попасть в очередь. Подождите, пока его предшественник разбудит его. Процесс честный.
4. Резюме
ReentrantLock
Разница между честными блокировками и нечестными блокировками вlock
Когда метод получает блокировку要不要判断 AQS 队列中是否有等待的线程
, Справедливая блокировка Для того, чтобы позволить каждому потоку использовать блокировку равномерно, ее нужно судить, если есть, отдайте ее ему, нечестная блокировка очень властная, не позволите - не позволите .
Но если он выйдет из строя и попадет в очередь, запись будет следовать логике AQS, и общий порядок будет справедливым.
Следует отметить еще один момент:ReentrantLock
изtryLock(无超时机制)
Несправедливая стратегия, используемая методом. соответствовать его дизайну.
а такжеtryLock(long timeout, TimeUnit unit)
Метод будет вызываться в соответствии с конкретной реализацией Sync. никаких импульсивных звонковnonfairTryAcquire
метод.