深度解析synchronized的实现原理(并发一)
一、synchronized实现原理
1、synchronized实现同步的基础:
1)、普通同步方法:锁是当前实例对象
2)、静态同步方法:锁是当前类的class对象
3)、同步方法块:锁是括号里面的对象
2、同步代码块、同步方法示例:
step1:同步代码块:
public class SynchronizedTest { public synchronized void test1(){ } public void test2(){ synchronized (this){ } } }
step2:javap(jdk工具包命令)查看生成的class文件信息分析synchronize的实现
class文件信息如下:
分析:同步代码块是使用monitorenter和monitorexit指令(jvm指令)实现的
同步代码块分析:monitorenter指令插到同步代码块开始的位置
monitorexit指令插到同步代码块结束的位置
每个对象有一个与之相关联的monitor
当且一个monitor被持有之后,对象被锁定
线程执行到monitorenter指令时,获取对象对应的monitor所有权(即获取对象的锁)
同步方法分析:synchronized方法被翻译成普通方法调用+返回指令
无任何指令实现被synchronized修饰的方法
在class文件的方法表中将该方法的access_flags字段中的synchronized字段标志1——》以此付方式表明该方法时同步方法
——》使用调用该方法的对象做为锁对象
二、由上面引出的两个重要概念(实现synchronized的基础)
1、Java对象头
对象头数据结构:
java对象头包含:Mark Word(标记字段)、Kass Pointer(类型指针)
Kass Pointer:
概念:对象指向它的类元数据的指针
作用:虚拟机通过这个指针确定这个对象是哪个类的实例
Mark Word:存储对象运行时的数据,是实现轻量级锁和指向锁的关键
存储数据有:哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳
2、Monitor
Monitor是一个同步工具,同步机制,是一个对象
所有的java对象都有成为Monitor的潜质
java对象有一把看不见的锁(内部锁或者Monitoe锁)
Monitor的数据结构:
Owner:保存拥有该锁的线程唯一标志
EntryQ:关联一个系统的互斥锁,阻塞试图锁住monitor record失败的线程
RcThis:表示阻塞或者等待在该monitor record上的线程个数
Nest:用来实现重入锁的计数
HashCode:保存从对象头拷过来的HashCode值
Candidate:用来避免不必要的阻塞和等待线程唤醒,有0(表示没有需要唤醒的线程)、1(表示要唤醒一个继任线程来竞争锁)