class SharedValue {
  private final Object monitor = new Object();
  private int value = 0;

  public void updateValue() {
    synchronized (monitor) {    // OK: 1回目のモニタロック獲得
      synchronized (monitor) {  // OK: 2回目のモニタロック獲得
        value += 1;
      } // モニタロック解放(2→1)
      value += 2;
    } // モニタロック解放(1→0)

  public void awaitValue() throws InterruptedException {
    synchronized (monitor) {
      synchronized (monitor) {
        while (value < 3) {
          // モニタロックを2回保持した状態でObject#waitを呼び出すと、
          // 全てのモニタロックを解放(2→0)してスレッド待機状態になる。
          // Object#waitメソッド呼び出しから制御が戻ってきたとき、
          // モニタロックを2回保持した状態(0→2)で処理継続する
      } // モニタロック解放(2→1)
    } // モニタロック解放(1→0)

Java Language Specification, Java SE 8 Editionより一部引用(下線部は強調)。

The Java programming language provides multiple mechanisms for communicating between threads. The most basic of these methods is synchronization, which is implemented using monitors. Each object in Java is associated with a monitor, which a thread can lock or unlock. Only one thread at a time may hold a lock on a monitor. Any other threads attempting to lock that monitor are blocked until they can obtain a lock on that monitor. A thread t may lock a particular monitor multiple times; each unlock reverses the effect of one lock operation.

Chapter 17. Threads and Locks, 17.1. Synchronization

Let thread t be the thread executing the wait method on object m, and let n be the number of lock actions by t on m that have not been matched by unlock actions. One of the following actions occurs:

  • If n is zero (i.e., thread t does not already possess the lock for target m), then an IllegalMonitorStateException is thrown.
  • (snip)
  • Otherwise, the following sequence occurs:
    1. Thread t is added to the wait set of object m, and performs n unlock actions on m.
    2. (snip)
    3. Thread t performs n lock actions on m.
    4. (snip)
Chapter 17. Threads and Locks, 17.2.1. Wait


*1:Java標準ライブラリ提供の java.util.concurrent.locks.ReentrantLock クラスと同じセマンティクス。ReentrantLock クラスから生成された Condition オブジェクトも、待機処理(Condition#await)で再帰ロックをサポートする。