Java知识进阶-程序员应该死磕的Monitor知识点-知识铺

科技 2020-01-08 15:17 阅读:64

一、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调度和分派的基本单位它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。