Как блокировка повторного входа помогает снова, когда у нас уже есть блокировка?

Таким образом, повторяющаяся блокировка увеличивает счет на единицу, если текущий поток снова получает блокировку. что я не могу понять, это почему и как это помогает или приносит пользу нам?

3 ответа

Причина, по которой это делает повторяющаяся блокировка, состоит в том, чтобы не блокировать тот же поток, который уже получил эту блокировку.

Например: Допустим, у вас есть Поток A, который получает блокировку Reentrant A. Чем Поток B пытается получить Блокировку A, что приведет к блокировке потока B (более подробную информацию о состояниях потока можно найти здесь). Теперь Поток А пытается (снова) получить Замок А.

Поскольку блокировка Reentrant теперь увеличивается, поток A не блокируется. Поток А по-прежнему имеет доступ к замку и может продолжать (в замках хранится информация о глубине). Если он (рано или поздно) снимает блокировку, счет снова будет снижен, чтобы проверить, нужна ли еще потоке А блокировка или нет. Если счетчик становится равным 0, то есть поток A освобождается при каждом получении, поток B получает доступ через замок.

Без повторного входа вы бы сейчас оказались в тупике. Зачем? Потому что поток А имеет блокировку и будет ждать ее получения снова.


Параллелизм может быть действительно сложным, а вход помогает (немного) уменьшить эту сложность.

Смысл увеличения счетчика для блокировки заключается в том, чтобы отслеживать, сколько раз поток получал блокировку, чтобы блокировка фактически не снималась до тех пор, пока поток не сообщит о готовности снять блокировку столько же раз.

Предполагается, что команды для блокировки будут сопоставлены с командами для снятия блокировки.

Скажем, мой код входит в раздел кода А, который требует блокировки.

Затем, не выходя из раздела кода A, он входит в раздел кода B, который также требует такой же блокировки. Как вы заметили, у нас есть блокировка, поэтому нам не нужно блокировать.

Но мы оставим Раздел B, и Раздел B написан для снятия блокировки при выходе из нее. (В противном случае код, который достигает Раздела B без блокировки, никогда не снимет блокировку.)

Мы все еще в Разделе A, поэтому мы не хотим по- настоящему снимать блокировку, иначе другой поток может снять ее, пока мы в Разделе A.

Поэтому, когда мы вошли в Раздел B, мы увеличили счетчик блокировок, что означает, что при выходе из Раздела B мы можем уменьшить счетчик на единицу и, увидев, что он не вернулся к 0, не освободить его.

Затем, когда Секция A снова снимает блокировку, счет возвращается к 0, и тогда мы действительно отпускаем блокировку.

Это помогает в необычной ситуации, когда вы хотите вызвать другой метод, который также требует блокировки.

ReentrantLock lock = new ReentrantLock();

public void doSomething() {
    lock.lock();
    try {
        // Something.
    } finally {
        lock.unlock();
    }
}

public void somethingElse () {
    lock.lock();
    try {
        // Something else.
        // We can now call another locking method without risking my lock being released.
        doSomething();
    } finally {
        lock.unlock();
    }
}

Здесь публика может позвонить doSomething и он получит блокировку, сделает свое дело и затем снимет блокировку, когда unlock называется.

Однако когда somethingElse называется и вызывает doSomething это только увеличивает количество блокировок. когда doSomething разблокирует, он не снимает блокировку, он просто считает отсчет блокировки, оставляя окончательную разблокировку в somethingElse снять замок.

Другие вопросы по тегам