文章目录
synchronized到底锁的是什么
可分为三种情况
记住:synchronized不可以锁静态代码快
1.代码块
此时锁的是括号中的变量/类,一般我们习惯写成this,此时锁的是当前类的实例化对象,如果多个线程用的是一个实例化对象,此时就一个线程拿到锁,其他线程无法访问,但是如果是每个线程都用每个线程实例化的对象,此时就不会线程线程同步。
2.普通方法
此时synchronized锁的是调用该方法的对象
3.静态方法
此时锁的是该方法所在的类
monitor结构:
要想理解的原理首先需要理解对象头
在JVM中,对象在内存中的布局分为三块区域:对象头、实例数据和对齐填充
实例变量:存放类的属性数据信息,包括父类的属性信息,如果是数组的实例部分还包括数组的长度,这部分内存按4字节对齐。
填充数据:由于虚拟机要求对象起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐,这点了解即可。
对象头:
1.运行时元数据:哈希值,GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID,偏向时间戳
2.类型指针,指向类元数据InstanceKlass,确定对象所属类型
3.如果是数组,还需要记录数组的长度
synchronized使用的锁对象是存储在Java对象头里的
其中Mark Word在默认情况下存储着对象的HashCode、分代年龄、锁标记位等以下是64位JVM的Mark Word默认存储结构
每个对象都存在着一个 monitor 与之关联,对象与其 monitor 之间的关系有存在多种实现方式,如monitor可以与对象一起创建销毁或当线程试图获取对象锁时自动生成,但当一个 monitor 被某个线程持有后,它便处于锁定状态。在Java虚拟机(HotSpot)中,monitor是由ObjectMonitor实现的,其主要数据结构如下 (位于HotSpot虚拟机源码ObjectMonitor.hpp文件,C++实现的)
objectMoniter结构
ObjectMonitor() {
_header = NULL;
_count = 0; //记录个数
_waiters = 0<