Java Lock.lock() и Lock.lockInterruptably()

Я хотел бы знать, как блокировки реализованы в Java. В некоторых учебниках я обнаружил, что они должны быть реализованы с использованием wait() и notify()/notifyAll() и некоторых логических флагов (это может быть намного сложнее, но в основном это должно быть так)

class SimpleLock {

  private boolean locked=false;

  public synchronized void lock() throws InterruptedException {
    while (locked)
      wait();
    locked=true;
  }

  public synchronized void unlock() throws InterruptedException {
    locked=false;
    notify();
  }

} 

но я знаю, что интерфейс Lock определяет два метода: Lock.lock(), который не может быть прерван, и Lock.lockInterruptably(), который может и выдает InterruptedException, чтобы иметь дело с даже.

Если бы блокировки были реализованы с помощью wait(), не должны ли они быть прерваны вызовом Thread.interrupt()?

Так как же на самом деле реализованы блокировки? Я думаю, что они основаны на других низкоуровневых средствах синхронизации Java (например, synchronized и wait()/notify()), но я не знаю, как это сделать.


person Luca    schedule 20.01.2016    source источник
comment
Я проголосовал за закрытие, так как думаю, что на SO нельзя ответить. Блокировка сложна и далеко не тривиальна. Борис дал ссылку на источник, но полное объяснение было бы (ИМХО) слишком широким для ТАК. Но как я уже сказал - только мое мнение.   -  person Fildor    schedule 20.01.2016
comment
@Fildor Мне не нужно подробное объяснение внутренней работы блокировки Java. Я просто хочу большую картину   -  person Luca    schedule 20.01.2016


Ответы (1)


Блокировки реализованы с использованием другой техники. Они используют AbstractQueuedSynchronizer под капотом. Он использует LockSupport.park. (), который вызывает функцию public native void park(boolean var1, long var2) Unsafe.

На самом деле потоки, ожидающие в Lock.lock(), все еще могут быть прерваны, но это не будет показано пользователю, потому что InterruptedException не будет выброшено. Поток проснется после прерывания, затем очистит флаг прерывания и снова попытается получить ту же блокировку.

Lock.lockInterruptibly() действует по-другому, когда происходит прерывание, оно генерирует исключение, поэтому пользователь может обрабатывать его так, как он хочет.

person dezhik    schedule 20.01.2016
comment
Итак, в конце концов, низкоуровневая синхронизация - это основа? - person Luca; 20.01.2016
comment
@Luca Не уверен, что именно вы определяете как низкоуровневую синхронизацию, но если вы будете копать глубже и глубже, вы рано или поздно, вероятно, окажетесь в собственном вызове. Это то, что вы хотели знать? - person Fildor; 20.01.2016
comment
Да, я немного отредактировал свой ответ - низкоуровневая синхронизация в этом случае будет функцией Unsafe public native void park(..) - person dezhik; 20.01.2016
comment
@Fildor извините, нет, то, что я имел в виду под низкоуровневой синхронизацией, было не таким уж низким уровнем ... Я имел в виду средства низкоуровневой синхронизации JAVA, такие как wait () / notify () или синхронизированный код. Как оказалось, это реализовано как низкоуровневые системные вызовы/собственный код, не так ли? - person Luca; 20.01.2016
comment
...Поток пробудится после прерывания... Это заблуждение. Поток, прерванный во время блокировки в Lock.lock(), не проснется из-за прерывания: он проснется, если и когда сможет получить блокировку. - person Solomon Slow; 20.01.2016
comment
На самом деле вы ошибаетесь, lock() реализован с использованием LockSupport.park(..), а в JavaDoc сказано, что park() возвращается, когда: какой-то другой поток вызывает unpark с текущим потоком в качестве цели; или какой-то другой поток прерывает текущий поток; или Вызов ложно (то есть без причины) возвращается. Таким образом, прерывание разбудит его, но после этого условие будет проверено, и произойдет другой парк (..). - person dezhik; 20.01.2016