File tree Expand file tree Collapse file tree 1 file changed +17
-1
lines changed
languages/java/mutil-thread Expand file tree Collapse file tree 1 file changed +17
-1
lines changed Original file line number Diff line number Diff line change @@ -5,11 +5,27 @@ synchronized关键字最主要有以下3种应用方式,下面分别介绍:
55- 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
66- 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
77- 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。
8-
8+ https://blog.csdn.net/javazejian/article/details/72828483
99synchronized底层语义原理:
1010对象在内存中的布局分为三块区域:对象头、实例数据和对齐填充
11+ Java 虚拟机中的同步(Synchronization)基于进入和退出管程(Monitor)对象实现, 无论是显式同步(有明确的 monitorenter 和 monitorexit 指令,即同步代码块)还是隐式同步都是如此。在 Java 语言中,同步用的最多的地方可能是被 synchronized 修饰的同步方法。
12+ 同步方法 并不是由 monitorenter 和 monitorexit 指令来实现同步的,而是由方法调用指令读取运行时常量池中方法的 ACC_SYNCHRONIZED 标志来隐式实现的,关于这点,稍后详细分析。下面先来了解一个概念Java对象头,这对深入理解synchronized实现原理非常关键。
13+
14+ 实例变量:存放类的属性数据信息,包括父类的属性信息,如果是数组的实例部分还包括数组的长度,这部分内存按4字节对齐。
15+ 填充数据:由于虚拟机要求对象起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐,这点了解即可。
16+ 而对于顶部,则是Java头对象,它实现synchronized的锁对象的基础,这点我们重点分析它,一般而言,synchronized使用的锁对象是存储在Java对象头里的,jvm中采用2个字来存储对象头(如果对象是数组则会分配3个字,多出来的1个字记录的是数组长度),其主要结构是由Mark Word 和 Class Metadata Address 组成,其结构说明如下表
17+
18+ 虚拟机位数 头对象结构 说明
19+ 32/64bit Mark Word 存储对象的hashCode、锁信息或分代年龄或GC标志等信息
20+ 32/64bit Class Metadata Address 类型指针指向对象的类元数据,JVM通过这个指针确定该对象是哪个类的实例。
1121
22+ 其中Mark Word在默认情况下存储着对象的HashCode、分代年龄、锁标记位等以下是32位JVM的Mark Word默认存储结构
23+ 锁状态 25bit 4bit 1bit是否是偏向锁 2bit 锁标志位
24+ 无锁状态 对象HashCode 对象分代年龄 0 01
1225
26+ 其中轻量级锁和偏向锁是Java 6 对 synchronized 锁进行优化后新增加的,稍后我们会简要分析。这里我们主要分析一下重量级锁也就是通常说synchronized的对象锁,锁标识位为10,其中指针指向的是monitor对象(也称为管程或监视器锁)的起始地址。每个对象都存在着一个 monitor 与之关联,对象与其 monitor 之间的关系有存在多种实现方式,如monitor可以与对象一起创建销毁或当线程试图获取对象锁时自动生成,但当一个 monitor 被某个线程持有后,它便处于锁定状态。在Java虚拟机(HotSpot)中,monitor是由ObjectMonitor实现的,其主要数据结构如下(位于HotSpot虚拟机源码ObjectMonitor.hpp文件,C++实现的)
27+ ObjectMonitor中有两个队列,_ WaitSet 和 _ EntryList,用来保存ObjectWaiter对象列表( 每个等待锁的线程都会被封装成ObjectWaiter对象),_ owner指向持有ObjectMonitor对象的线程,当多个线程同时访问一段同步代码时,首先会进入 _ EntryList 集合,当线程获取到对象的monitor 后进入 _ Owner 区域并把monitor中的owner变量设置为当前线程同时monitor中的计数器count加1,若线程调用 wait() 方法,将释放当前持有的monitor,owner变量恢复为null,count自减1,同时该线程进入 WaitSe t集合中等待被唤醒。若当前线程执行完毕也将释放monitor(锁)并复位变量的值,以便其他线程进入获取monitor(锁)。如下图所示
28+ 由此看来,monitor对象存在于每个Java对象的对象头中(存储的指针的指向),synchronized锁便是通过这种方式获取锁的,也是为什么Java中任意对象可以作为锁的原因,同时也是notify/notifyAll/wait等方法存在于顶级对象Object中的原因(关于这点稍后还会进行分析),ok~ ,有了上述知识基础后,下面我们将进一步分析synchronized在字节码层面的具体语义实现。
13292.关键字volatile
1430
15313.锁的分类
You can’t perform that action at this time.
0 commit comments