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。

 

转载:https://www.cnblogs.com/webor2006/p/11443392.html

posted @ 2019-12-31 10:20  朱子威  阅读(5874)  评论(2编辑  收藏  举报