Параллельное программирование - анализ исходного кода Fair Lock и Unfair Lock

задняя часть исходный код UML

предисловие

ReentrantLock предоставляет честные и нечестные блокировки, вам нужно использовать только одну из них в конструкторе.booleanпараметры. Несправедливая блокировка по умолчанию.

Сегодня давайте посмотрим на разницу и конкретную реализацию на уровне исходного кода.

1. UML-диаграмма класса

image.png

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;
}

Скажи логику:

  1. Получите переменную состояния, если она равна 0, блокировку можно получить.
  2. Определите, есть ли ожидающие потоки в очереди AQS., если нет, попробуйте получить его с помощью CAS. После успешного получения измените поток удержания CLH на текущий поток.
  3. Логика реентерабельной блокировки.
  4. В случае сбоя и возврата 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метод.