synchronized背后的monitor

获取和释放 monitor 锁的时机

最简单的同步方式就是利用 synchronized 关键字来修饰代码块或者修饰一个方法,那么这部分被保护的代码,在同一时刻就最多只有一个线程可以运行,而 synchronized 的背后正是利用 monitor 锁实现的。所以首先我们来看下获取和释放 monitor 锁的时机,每个 Java 对象都可以用作一个实现同步的锁,这个锁也被称为内置锁或 monitor 锁,获得 monitor 锁的唯一途径就是进入由这个锁保护的同步代码块或同步方法,线程在进入被 synchronized 保护的代码块之前,会自动获取锁,并且无论是正常路径退出,还是通过抛出异常退出,在退出的时候都会自动释放锁

public synchronized void method() {
    dosomething
}

等价伪代码
public void method() {
    this.intrinsicLock.lock();
    try {
        dosomething
    } finally {
        this.intrinsicLock.unlock();
    }
}

用 javap 命令查看反汇编的结果

JVM 实现 synchronized 方法和 synchronized 代码块的细节不一样

public class SyncTest {

    public void syncBlock() {
        synchronized (this) {
            System.out.println("sync Block");
        }
    }

    public synchronized void synMethod() {
        System.out.println("sync method");
    }
}

编译之后通过命令javap -verbose SyncTest.class查看
synchronized方法内的代码块

同步代码块

从里面可以看出,synchronized 代码块实际上多了 monitorenter 和 monitorexit 指令,标红的第3、13、19行指令分别对应的是 monitorenter 和 monitorexit。这里有一个 monitorenter,却有两个 monitorexit 指令的原因是,JVM 要保证每个 monitorenter 必须有与之对应的 monitorexit,monitorenter 指令被插入到同步代码块的开始位置,而 monitorexit 需要插入到方法正常结束处和异常处两个地方,这样就可以保证抛异常的情况下也能释放锁

由于这是可重入锁,所以在内部会用一个计数器来保存已经重入的次数。我们来具体看一下 monitorenter 和 monitorexit 的含义:

  • monitorenter

执行 monitorenter 的线程尝试获得 monitor 的所有权,会发生以下这三种情况之一:

  1. 如果该 monitor 的计数为 0,则线程获得该 monitor 并将其计数设置为 1。然后,该线程就是这个 monitor 的所有者。
  2. 如果线程已经拥有了这个 monitor ,则它将重新进入,并且累加计数。
  3. 如果其他线程已经拥有了这个 monitor,那个这个线程就会被阻塞,直到这个 monitor 的计数变成为 0,代表这个 monitor 已经被释放了,于是当前这个线程就会再次尝试获取这个 monitor。
  • monitorexit

monitorexit 的作用是将 monitor 的计数器减 1,直到减为 0 为止。代表这个 monitor 已经被释放了,已经没有任何线程拥有它了,也就代表着解锁,所以,其他正在等待这个 monitor 的线程,此时便可以再次尝试获取这个 monitor 的所有权。

synchronized加在代码块上加锁使用monitorenter,释放锁使用monitorexit

同步方法

synchronized加载方法上

synchronzed加在方法上会有一个ACC_SYNCHRONIZED标识。当某个线程要访问某个方法的时候,会首先检查方法是否有 ACC_SYNCHRONIZED 标志,如果有则需要先获得 monitor 锁,然后才能开始执行方法,方法执行之后再释放 monitor 锁。其他方面, synchronized 方法和刚才的 synchronized 代码块是很类似的,例如这时如果其他线程来请求执行方法,也会因为无法获得 monitor 锁而被阻塞。

学习交流q群:513650703

posted @ 2022-03-27 22:06  学无终  阅读(107)  评论(0编辑  收藏  举报