背景

  在jdk1.6以前synchronized的java内置锁不存在 偏向锁->轻量级锁->重量级锁 的锁膨胀机制,锁膨胀机制是1.6之后为了优化java线程同步性能而实现的。而1.6之前都是基于monitor机制的重量级锁。因为java内部对锁实现的封装,就算现在我们也只需要了解重量级锁就可以了。深入了解monitor机制对学习线程同步非常重要。

 

正文

  目录

  1. 什么是monitor
  2. monitor的作用
  3. monitor的组成
  4. 寻找monitor锁
  5. java monitor机制的实现

 

什么是monitor 参考

  monitor直译过来是监视器的意思,专业一点叫管程。monitor是属于编程语言级别的,它的出现是为了解决操作系统级别关于线程同步原语的使用复杂性,类似于语法糖,对复杂操作进行封装。而java则基于monitor机制实现了它自己的线程同步机制,就是synchronized内置锁。

 

monitor的作用

  monitor的作用就是限制同一时刻,只有一个线程能进入monitor框定的临界区,达到线程互斥,保护临界区中临界资源的安全,这称为线程同步使得程序线程安全。同时作为同步工具,它也提供了管理进程,线程状态的机制,比如monitor能管理因为线程竞争未能第一时间进入临界区的其他线程,并提供适时唤醒的功能。

 

monitor的组成

  3.1 monitor对象

    monitor对象是monitor机制的核心,它本质上是jvm用c语言定义的一个数据类型。对应的数据结构保存了线程同步所需的信息,比如保存了被阻塞的线程的列表,还维护了一个基于mutex的锁,monitor的线程互斥就是通过mutex互斥锁实现的。

  3.2 临界区

    临界区是被synchronized包裹的代码块,可能是个代码块,也可能是个方法。

  3.3 条件变量

    条件变量和下方wait signal方法的使用有密切关系 。在获取锁进入临界区之后,如果发现条件变量不满足使用wait方法使线程阻塞,条件变量满足后signal唤醒被阻塞线程。 tips:当线程被signal唤醒之后,不是从wait那继续执行的,而是重新while循环一次判断条件是否成立。参考

  3.4 定义在monitor对象上的wait() signal() signalAll()操作

 

java中monitor的实现

  4.1 首先先看一下synchronized同步代码块和同步方法编译后的字节码指令文件分别是什么样子

    源代码如下 

public class SynchronizedTest {
    public synchronized void test1(){
    }
    public void test2(){
        synchronized (this){
        }
    }
}

 

接着我们用javap查看

  java并发系列-monitor机制实现

 

   java并发系列-monitor机制实现

 

   

  从上面可以看出,同步方法jvm是使用ACC_SYNCHRONIZED方法访问标识符实现同步,同步代码块jvm是使用monitorenter和monitorexit指令包裹临界区实现同步。

  

  4.2 线程执行到同步方法处和同步代码块monitorenter和monitorexit指令分别发生了什么

    这里需要看jvm的官方文档,下面三段话要好好读一读,monitor的运行逻辑都包含在里面。

    同步方法 文档

2.11.10. Synchronization
The Java Virtual Machine supports synchronization of both methods and sequences of instructions within a method by a single synchronization construct: the monitor.

Method-level synchronization is performed implicitly, as part of method invocation and return (§2.11.8). A synchronized method is distinguished in the run-time constant pool's method_info structure (§4.6) by the ACC_SYNCHRONIZED flag, which is checked by the method invocation instructions. When invoking a method for which ACC_SYNCHRONIZED is set, the executing thread enters a monitor, invokes the method itself, and exits the monitor whether the method invocation completes normally or abruptly. During the time the executing thread owns the monitor, no other thread may enter it. If an exception is thrown during invocation of the synchronized method and the synchronized method does not handle the exception, the monitor for the method is automatically exited before the exception is rethrown out of the synchronized method.

Synchronization of sequences of instructions is typically used to encode the synchronized block of the Java programming language. The Java Virtual Machine supplies the monitorenter and monitorexit instructions to support such language constructs. Proper implementation of synchronized blocks requires cooperation from a compiler targeting the Java Virtual Machine (§3.14).

Structured locking is the situation when, during a method invocation, every exit on a given monitor matches a preceding entry on that monitor. Since there is no assurance that all code submitted to the Java Virtual Machine will perform structured locking, implementations of the Java Virtual Machine are permitted but not required to enforce both of the following two rules guaranteeing structured locking. Let T be a thread and M be a monitor. Then:

The number of monitor entries performed by T on M during a method invocation must equal the number of monitor exits performed by T on M during the method invocation whether the method invocation completes normally or abruptly.

At no point during a method invocation may the number of monitor exits performed by T on M since the method invocation exceed the number of monitor entries performed by T on M since the method invocation.

Note that the monitor entry and exit automatically performed by the Java Virtual Machine when invoking a synchronized method are considered to occur during the calling method's invocation.


2.11.10。同步化
Java虚拟机通过单个同步结构(监视器)支持方法和方法中指令序列的同步。

作为方法调用和返回的一部分,方法级同步是隐式执行的(第2.11.8节)。甲synchronized方法是在运行时间常量池中的区分method_info结构(§4.6由)ACC_SYNCHRONIZED标志,这是由方法调用指令进行检查。调用方法时ACC_SYNCHRONIZED设置为1时,无论方法调用是正常完成还是突然完成,执行线程都将进入监视器,调用方法本身并退出监视器。在执行线程拥有监视器的时间内,没有其他线程可以进入它。如果在调用synchronized方法期间引发了异常并且该synchronized方法不处理该异常,则在将该异常重新抛出该方法之前,该方法的监视器将自动退出synchronized。

指令序列的同步通常用于对synchronizedJava编程语言的块进行编码 。Java虚拟机提供了 monitorenter和monitorexit指令来支持这种语言构造。正确实现synchronized块需要目标Java虚拟机(第3.14节)的编译器的配合。

当方法调用期间,给定监视器上的每个出口与该监视器上的先前条目匹配时,就是结构锁定。由于不能保证提交给Java虚拟机的所有代码都将执行结构化锁定,因此允许但不要求强制执行以下两个保证结构化锁定的规则的Java虚拟机实现。设 T为线程, M为监视器。然后:

进行监控条目的数量由Ť上中号的方法调用期间必须等于由执行监控退出的数目Ť上中号 是否该方法调用完成正常或突然的方法调用期间。

在一个方法调用期间没有点可以通过执行监控退出的数目Ť 上中号,因为该方法的调用超过执行监视器条目的数量Ť 上中号,因为该方法调用。

请注意,在调用synchronized方法时,Java虚拟机在调用方法时自动执行的监视器进入和退出 被视为发生。
View Code

相关文章: