synchronized底层实现monitor详解
二、ObjectMonitor 结构
前面讲到 java.lang.Object 类定义了 wait(),notify(),notifyAll() 方法。 这些都是 native方法,底层是C++来实现的。 这些方法的具体实现,依赖一个叫做ObjectMonitor模式实现,这是JVM内部C++实现的机制。
这里有几个比较重要的字段
2.1 _owner 指向持有ObjectMonitor对象的线程地址。
2.2 _WaitSet 存放调用wait方法,而进入等待状态的线程的队列。
2.3 _EntryList 这里是等待锁block状态的线程的队列。
2.4 _recursions 锁的重入次数。
2.5 _count 线程获取锁的次数。
三、 Monitor 上锁 释放锁
3.1 上锁过程
3.1.1 线程获取资源对象的锁,判断 _owner是否为空。这里操作是通过 CAS操作:比较和交换(Conmpare And Swap),比较新值和旧值的不同,替换,这里会发生ABA问题,接下来文章会详细说明。
3.1.2 如果 _owner为null ,直接把其赋值,指向自己, _owner = self ,同时把重入次数 _recursions = 1, 获取锁成功。
3.1.3 如果 _self == cur 和当前线程一致,说明是重入了, _recursions++ 即可
3.1.4 线程进入对象资源,处理。 同时等待当前线程的释放信号,期间一致持有对象资源的锁。
3.2 释放锁
3.2.1 通过 ObjectMonitor::exit 退出
3.2.2 把线程插入到_EntryList中 _recursions--
3.2.3 再次从 _EntryList 中取出线程
3.2.4 调用unpark退出
在我们分析synchronized关键字底层信息时,其中谈到了Monitor对象,它是由C++来实现的,那,到底它长啥样呢?我们在编写同步代码时完全木有看到该对象的存在,所以这次打算真正来瞅一下它的真正面目,而对于这个Hospot代码JDK是并没有开源的,但是社区版本的JDK是开源了,在openjdk上可以阅读得到,所以下面先到openjdk上瞅一下:
所以点击一下它:
点击一下:
然后点击左侧的browser方便我们浏览代码:
然后定位到这个路径:
然后点击runtime/,
其中,我们要想看到Monitor对象的源代码就在其中,如下:
其中.hpp是c++的头文件,其具体的实现是以cpp中,接下来就得打开它们来看我们想了解的东东了,是不是很刺激?对于上一次理论中提到了两个东东:
那咱们从源码中来看一下具体都表现为啥,首先先来看一下ObjectMonitor.hpp:
接下来就可以看到ObjectMonitor的类声明了:
其实对就对应于:
接下来挑里面的重点内容瞅一下:
接下来看一下它的成员变量:
那看一下_WaitSet的定义:
再看一下_EntryList的定义:
另外在上一个理论中提到了:
其实也在底层有定义,如下:
看一下它的定义:
另外上理论中还提到了它:
其实也有对应:
继续来看其它的一个成员变量:
对于wait()和notify()的底层细节到底是啥样的呢?下面还是先来到openjdk中来打开ObjectMonitor.hpp,其中它里面有一个很重要的类:
然后我们要分析的wait()和notify()是在它的cpp实现文件中,所以打开ObjectMonitor.cpp来直奔主题:
其中我们在Java层看到的wait()方法的最终实现就是这个cpp中的这个方法:
先纵览一下该方法的实现,代码量比较多,有将近200多行的代码,全部看通是不可能的,挑重点的来看:
而Self其实是一个线程:
所以这句话的是将线程包装成了ObjectWaiter对象了:
另外会将状态改为等待状态:
另外,在上次的理论中我们知道在调用了wait()之后,会将其加入到WaitSet当中,如:
那么。。具体对应的底层代码在哪呢?看下面:
好,下面来瞅一下它的具体实现:
再回到wait()方法继续,其中可以看到有自旋锁的东东:
下面简单的纵览一下它:
好,下面再来观测一下notify()方法的细节:
咱们看一下DequeueWaiter()方法是怎么实现的:
回到主流程:
其实在notify()的官网中也有类似的说明:
而文档中提到的“具体实现”其实就是如我们看到cpp中这块的代码,不同的策略其实现也不一样。
照我们之前的理论来说,唤醒的线程会被放到EntryList当中:
在notify()代码中也能看到:
然后最后会看到有一个这个代码:
以上就是从底层c++的角度来审视我们在java上调用的wait()和notify()的具体细节,虽说大致看了一下主流程,实际工作也没啥大的作用,但是!!!对我们的更深入的理解起到了非常重要的作用,毕境可以让你能更加自信的用Java的这些API。