synchronized的用法;synchronized实现原理
  l4ISZxe3viJz 2023年11月02日 36 0

一、synchronized

synchronized用来保证代码的原子性,通常有三种用法:

1.1修饰实例方法

作用于当前对象实例枷锁,进入同步代码前要获得当前对象实例的锁。

synchronized void method() {
	//业务代码
}

1.2修饰静态方法

给当前类枷锁,会作用于类的所有对象实例,进入同步代码前要获得当前class的锁,因为静态成员不属于任何一个对象,是类成员(static表明这是该类的一个静态资源,不管new了多少个对象,只有一份)。

如果一个线程A调用一个实例对象的非静态synchronized方法,而线程B需要调用这个实例对象所属类的静态synchronized方法,是允许的,不会发生互斥现象,因为访问静态synchronized修饰的方法占用的是当前类的锁,而访问非静态synchronized方法占用的是当前实例对象的锁。

synchronized void static method(){
  //方法体
}

1.3修饰代码块

指定加锁对象,对给定对象/类加锁。

synchronized(this/object)表示进入同步代码库前要获得给定对象的锁。

snychronized(类.class)表示进入同步代码前要获得当前class的锁。

synchronized(this){
  //业务代码
}

二、synchronized实现原理

2.1synchronized是怎么加锁的?

使用synchronized不用自己lock和unlock,因为JVM帮我们把这个事情做了。

1、synchronized修饰代码块时,JVM采用monitorenter、moniterexit两个指令来实现同步,monitorenter指令指向同步代码块的开始,monitorexit指令指定同步代码块的结束位置。

反编译一段synchronized修饰的代码块:

javap -c -s -v -l SynchronizedDemo.class

可以看到相应的字节码指令:

synchronized的用法;synchronized实现原理_加锁

2、synchronized修饰同步方法时,JVM采用ACC_SYNCHRONIZED标记符来实现同步,这个标识指明了该方法是一个同步方法。

反编译代码如下:

synchronized的用法;synchronized实现原理_代码块_02

2.2synchronized锁住的是什么

monitorenter、moniterexit或者ACC_SYNCHRONIZED都是基于Monitor实现的。

实例对象结构里有对象头,对象头里面有一块结构叫Mark Word,Mark Word指针指向了monitor。

所谓的Monitor其实是一种同步工具,也可以说是一种同步机制。在Java虚拟机(HotSpot)中,Monitor是由ObjectMonitor实现的,可以叫做内部锁,或者Monitor锁。

ObjectMonitor的工作原理:

ObjectMonitor有两个队列:WaitSet、EntryList,用来保存ObjectWaiter对象列表;

_owner,获取Monitor对象的线程进入_owner区时,_count+1。如果线程调用了wait()方法,此时会释放Monitor对象,_owner恢复为空,_count-1。同时该等待线程进入_WaitSet中,等待被唤醒。

ObjectMonitor() {
  _header = NULL;
  _count = 0; // 记录线程获取锁的次数
  _waiters = 0,
  _recursions = 0; //锁的重入次数
  _object = NULL;
  _owner = NULL; // 指向持有ObjectMonitor对象的线程
  _WaitSet = NULL; // 处于wait状态的线程,会被加入到
  _WaitSet
  _WaitSetLock = 0 ;
  _Responsible = NULL ;
  _succ = NULL ;
  _cxq = NULL ;
  FreeNext = NULL ;
  _EntryList = NULL ; // 处于等待锁block状态的线程,会被加入
  到该列表
  _SpinFreq = 0 ;
  _SpinClock = 0 ;
  OwnerIsThread = 0 ;
}

可以类比一个去医院就诊的例子:

首先,患者在门诊大厅前台或自助挂号机进行挂号;

随后,挂号结束后患者找到对应的诊室就诊:

诊室每次只能有一个患者就诊;

如果此时诊室空闲,直接进入就诊;

如果此时诊室内有其它患者就诊,那么当前患者进入候诊室,等待叫号;

就诊结束后,走出就诊室,候诊室的下一位候诊患者进入就诊室。

synchronized的用法;synchronized实现原理_代码块_03

这个过程和Monitor机制比较相似:

门诊大厅:所有待进入的线程都必须先在入口Entry Set 挂号才有资格;

就诊室:就诊室_Owner 里里只能有一个线程就诊,就诊完线程就自行离开

候诊室:就诊室繁忙时,进入等待区(Wait Set) ,就诊室空闲的时候就从等

待区(Wait Set) 叫新的线程

synchronized的用法;synchronized实现原理_JVM_04

那么,同步锁到底锁的是什么呢?

monitorenter,在判断拥有同步标识ACC_SYNCHRONIZED抢先进入此方法的线程会优先拥有Monitor和owner,此时计算器+1。

monitorexit,当执行完退出后,计数器-1,归0后被其他进入的线程获得。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
l4ISZxe3viJz