一、Moniter 场景
1.1 Java 线程同步
由于多线程对资源的访问引发的可见性和原子性带来的安全问题。同步锁,互斥锁,都可以保证同一时刻只有一个线程访问。 这里用到的机制就是都是对资源的监视锁,即Monitor,每个对象都用于自己的监视锁Monitor.
1.2 对象中的锁标识
在Java 对象模型中讲到,每个对象的头部都有三部分组成:Mark Word 、Klass Word、数组长度。 每个对象的锁标识,就在 Mark Word这部分中。 如下图:
二、ObjectMonitor 结构
前面讲到 java.lang.Object 类定义了 wait,notify,notifyAll 方法。 这些都是 native方法,底层是C++来实现的。 这些方法的具体实现,依赖一个叫做ObjectMonitor模式实现,这是JVM内部C++实现的机制。
这里有几个比较重要的字段
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退出
具体代码,可以搜索 objectMonitor.cpp ,查看源码。
本文相关词条概念解析:
线程
线程,计算机科学术语,有时也被称为轻量级进程(Light Weight Process,LWP),它是运行中的程序的调度单位。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。线程被包含在进程之中,是进程的一个实体,是CPU调度和分派的基本单位它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。