1、Java 对象头

以 32 位虚拟机为例

普通对象

|--------------------------------------------------------------|
|                     Object Header (64 bits)                  |
|------------------------------------|-------------------------|
|        Mark Word (32 bits)         |    klass Word (32 bits) |
|------------------------------------|-------------------------|

数组对象

|---------------------------------------------------------------------------------|
|                                 Object Header (96 bits)                         |
|--------------------------------|-----------------------|------------------------|
|        Mark Word(32bits)       |    Klass Word(32bits) |  array length(32bits)  |
|--------------------------------|-----------------------|------------------------|

其中 Mark Word 结构为

|-------------------------------------------------------|--------------------|
|                  Mark Word (32 bits)                  |       State        |
|-------------------------------------------------------|--------------------|
|  hashcode:25         | age:4 | biased_lock:0 | 01     |       Normal       |
|-------------------------------------------------------|--------------------|
|  thread:23 | epoch:2 | age:4 | biased_lock:1 | 01     |       Biased       |
|-------------------------------------------------------|--------------------|
|               ptr_to_lock_record:30          | 00     | Lightweight Locked |
|-------------------------------------------------------|--------------------|
|               ptr_to_heavyweight_monitor:30  | 10     | Heavyweight Locked |
|-------------------------------------------------------|--------------------|
|                                              | 11     |    Marked for GC   |
|-------------------------------------------------------|--------------------|

64 位虚拟机 Mark Word

|--------------------------------------------------------------------|--------------------|
|                        Mark Word (64 bits)                         |       State        |
|--------------------------------------------------------------------|--------------------|
| unused:25 | hashcode:31 | unused:1 | age:4 | biased_lock:0 | 01    |       Normal       |
|--------------------------------------------------------------------|--------------------|
| thread:54 | epoch:2     | unused:1 | age:4 | biased_lock:1 | 01    |       Biased       |
|--------------------------------------------------------------------|--------------------|
|             ptr_to_lock_record:62                          | 00    | Lightweight Locked |
|--------------------------------------------------------------------|--------------------|
|             ptr_to_heavyweight_monitor:62                  | 10    | Heavyweight Locked |
|--------------------------------------------------------------------|--------------------|
|                                                            | 11    |    Marked for GC   |
|--------------------------------------------------------------------|--------------------|

参考资料

https://stackoverflow.com/questions/26357186/what-is-in-java-object-header

2、Monitor 原理

Monitor 被翻译为监视器管程

每个 Java 对象都可以关联一个 Monitor 对象,如果使用 synchronized 给对象上锁(重量级)之后,该对象头的 Mark Word 中就被设置指向 Monitor 对象的指针

Monitor 结构如下

  • 刚开始 Monitor 中 Owner 为 null

  • 当 Thread-2 执行 synchronized(obj) 就会将 Monitor 的所有者 Owner 置为 Thread-2,Monitor中只能有一个 Owner

  • 在 Thread-2 上锁的过程中,如果 Thread-3,Thread-4,Thread-5 也来执行 synchronized(obj),就会进入 EntryList BLOCKED

  • Thread-2 执行完同步代码块的内容,然后唤醒 EntryList(阻塞队列) 中等待的线程来竞争锁,竞争是非公平的

  • 图中 WaitSet 中的 Thread-0,Thread-1 是之前获得过锁,但条件不满足进入 WAITING 状态的线程,后面讲 wait-notify 时会分析

注意:

  • synchronized 必须是进入同一个对象的 monitor 才有上述的效果

  • 不加 synchronized 的对象不会关联监视器,不遵从以上规则

3、synchronized 原理

static final Object lock = new Object();
static int counter = 0;

public static void main(String[] args) {
   synchronized (lock) {
       counter++;
  }
}

对应的字节码为

public static void main(java.lang.String[]);
   descriptor: ([Ljava/lang/String;)V
   flags: ACC_PUBLIC, ACC_STATIC
   Code:
     stack=2, locals=3, args_size=1
        0: getstatic     #2                  // <- lock引用 (synchronized开始)
        3: dup                               // 复制一份引用
        4: astore_1                          // lock引用 -> slot 1
        5: monitorenter                      // 将 lock对象 MarkWord 置为 Monitor 指针
        6: getstatic     #3                  // <- i
        9: iconst_1                          // 准备常数 1
       10: iadd                              // +1
       11: putstatic     #3                  // -> i
       14: aload_1                           // <- lock引用
       15: monitorexit                       // 将 lock对象 MarkWord 重置, 唤醒 EntryList
       16: goto          24  // 19-23 为异常处理
       19: astore_2                          // e -> slot 2
       20: aload_1                           // <- lock引用
       21: monitorexit                       // 将 lock对象 MarkWord 重置, 唤醒 EntryList
       22: aload_2                           // <- slot 2 (e)
       23: athrow                            // throw e
       24: return
     Exception table: // 异常检测
        from    to  target type
            6    16    19   any // 6-16 行出现异常 目标为19行
           19    22    19   any // 19-22 行出现异常 目标为19行
     LineNumberTable:
       line 8: 0
       line 9: 6
       line 10: 14
       line 11: 24
     LocalVariableTable:
       Start  Length  Slot  Name   Signature
           0      25     0  args   [Ljava/lang/String;
     StackMapTable: number_of_entries = 2
       frame_type = 255 /* full_frame */
         offset_delta = 19
         locals = [ class "[Ljava/lang/String;", class java/lang/Object ]
         stack = [ class java/lang/Throwable ]
       frame_type = 250 /* chop */
         offset_delta = 4

注意

方法级别的 synchronized 不会在字节码指令中有所体现

Java并发(十九)----Monitor原理及Synchronized原理的更多相关文章

  1. Java 并发编程:volatile的使用及其原理

    Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...

  2. Java 并发编程——Executor框架和线程池原理

    Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务 ...

  3. Java并发编程-阻塞队列(BlockingQueue)的实现原理

    背景:总结JUC下面的阻塞队列的实现,很方便写生产者消费者模式. 常用操作方法 常用的实现类 ArrayBlockingQueue DelayQueue LinkedBlockingQueue Pri ...

  4. “全栈2019”Java第九十九章:局部内部类与继承详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  5. Java 并发编程——Executor框架和线程池原理

    Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...

  6. “全栈2019”Java第二十九章:数组详解(中篇)

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  7. “全栈2019”Java第十九章:关系运算符、条件运算符和三元运算符

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  8. Java并发(十九):final实现原理

    final在Java中是一个保留的关键字,可以声明成员变量.方法.类以及本地变量. 一旦你将引用声明作final,你将不能改变这个引用了,编译器会检查代码,如果你试图将变量再次初始化的话,编译器会报编 ...

  9. Java并发编程之深入理解线程池原理及实现

    Java线程池在实际的应用开发中十分广泛.虽然Java1.5之后在JUC包中提供了内置线程池可以拿来就用,但是这之前仍有许多老的应用和系统是需要程序员自己开发的.因此,基于线程池的需求背景.技术要求了 ...

  10. 【转】Java 并发编程:volatile的使用及其原理

    一.volatile的作用 在<Java并发编程:核心理论>一文中,我们已经提到过可见性.有序性及原子性问题,通常情况下我们可以通过Synchronized关键字来解决这些个问题,不过如果 ...

随机推荐

  1. 浅谈API安全的应用

    ​ 理论基础 API它的全称是Application Programming Interface,也叫做应用程序接口,它定义了软件之间的数据交互方式.功能类型.随着互联网的普及和发展,API 从早期的 ...

  2. 如何像 Sealos 一样在浏览器中打造一个 Kubernetes 终端?

    作者:槐佳辉.Sealos maintainer 在 Kubernetes 的世界中,命令行工具(如 kubectl 和 helm)是我们与集群交互的主要方式.然而,有时候,我们可能希望能够在 Web ...

  3. KRPANO最新完整汉化中文版 (KRPANO-1.19-PR10-WIN汉化版)

    KRPano 最新版本汉化krpano-1.19-pr10-win,由KRPano技术解密群:551278936 提供. 下载地址:http://pan.baidu.com/s/1bBmD5c 如果需 ...

  4. python实现简单的爬虫功能

    前言Python是一种广泛应用于爬虫的高级编程语言,它提供了许多强大的库和框架,可以轻松地创建自己的爬虫程序.在本文中,我们将介绍如何使用Python实现简单的爬虫功能,并提供相关的代码实例. 如何实 ...

  5. k8s 自动扩缩容HPA原理及adapter配置详解👑

    大家好,我是蓝胖子,都知道,k8s拥有自动扩缩容机制HPA,我们能够通过配置针对不同的扩缩容场景进行自动扩缩容,往往初学者在面对其中繁多配置的时候会学了又忘记,今天我将会以一种不同的视角,结合api ...

  6. 其它——ASCII码,Unicode和UTF-8编码

    文章目录 一 ASCII码 二 非ASCII编码 三 Unicode 3.1 Unicode存在的问题 3.2 它们造成的结果是 四 UTF-8 4.1 UTF-8 特点 4.2 UTF-8 的编码规 ...

  7. 下载、安装CAN-EYE植被参数工具

      本文介绍植被指数计算软件CAN-EYE的下载.安装方法.   CAN-EYE软件是由法国国家农业研究院(French National Institute of Agricultural Rese ...

  8. 2020/4/29 一场令人头疼的cf。。。

    今天是被安排的cf...我真的是太菜了啊...又双叒叕被机房的一群dalao吊打了... 这就是我与6年级的dalao的区别吗...我裂开了 T1:A - Exercising Walk 简单题. 就 ...

  9. 4款.NET开源的Redis客户端驱动库

    前言 今天给大家推荐4款.NET开源免费的Redis客户端驱动库(以下排名不分先后). Redis是什么? Redis全称是REmote DIctionary Service,即远程字典服务.Redi ...

  10. MQ系列15:MQ实现批量消息处理

    MQ系列1:消息中间件执行原理 MQ系列2:消息中间件的技术选型 MQ系列3:RocketMQ 架构分析 MQ系列4:NameServer 原理解析 MQ系列5:RocketMQ消息的发送模式 MQ系 ...