synchronize的实现原理

本文详细解析了Java中锁的工作原理,包括偏向锁、轻量级锁和重量级锁的状态转换,以及自旋锁和自适应自旋锁的优缺点。通过理解MarkWord的结构,我们能更好地掌握锁的升级过程。

参考:

https://blog.youkuaiyun.com/u012715840/article/details/58247556

https://blog.youkuaiyun.com/East_MrChiu/article/details/89163865

 

总结 : 1. 对象锁标记初始值为匿名偏向锁

2. 线程第一次获取锁是升级为偏向锁

3. 不止一个线程获取偏向锁,CAS 线程Id 失败的时候,升级为轻量级锁

4. 并发线程数太多,轻量级锁在CAS Mark Word 值失败时 升级为重量级锁,线程阻塞

问题答案
synchronize 锁

同步代码块是使用monitorenter和monitorexit指令实现的

synchronize用的锁存储在Java对象头里

无状态锁,偏向锁,轻量级锁和重量级锁状态

32位 Mard Word

25 bit 对象hashCode 4bit 分代年龄 1bit 是否偏向锁 2bit 锁标志位

自旋锁

自适应自旋锁

自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁

优点: 不会引起调用者睡眠 缺点:一直占用CPU(可通过自旋次数及挂起线程来解决)

自适应自旋锁:自旋的时间限度不是一个固定值,由上一次同一个锁的自旋时间及锁的拥有者状态来决定

偏向锁

JVM启用了偏向锁模式(JDK6以上默认开启),新创建对象的Mark Word是未锁定,未偏向但可偏向状态,此时Mark Word中的Thread id为0,表示未偏向任何线程,也叫做匿名偏向(anonymously biased)

获取锁

1.第一个线程1尝试进入同步块时,Mark Word中线程ID为0,CAS将自己的线程ID设置到Mark Word中(偏向锁仅会执行一次CAS),在当前线程栈中由高到低顺序找到可用的Lock Record,将线程ID记录下

2.线程1再次进入同步块时,往当前线程的栈中添加一条Displaced Mark Word为空的Lock Record中,用来统计重入的次数,执行同步代码块

3.线程2进入同步块时,发现Mark Word中线程ID与自己不相符,这个时候就会引发偏向锁的撤销,线程2 CAS 操作竞争锁。

如果成功,则改写Mark Word 线程ID;继续是偏向锁

如果失败,当到达全局安全点时,线程1挂起,锁升级为轻量级锁,线程1唤醒继续执行

 

释放锁(竞争锁的时候才会释放)

偏向锁只有遇到其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,线程不会主动去释放偏向锁。偏向锁的撤销,需要等待全局安全点(在这个时间点上没有字节码正在执行)它会首先暂停拥有偏向锁的线程,判断锁对象是否处于被锁定状态,撤销偏向锁后恢复到未锁定(标志位为“01”)或轻量级锁(标志位为“00”)的状态。

偏向锁撤销

偏向锁释放

参考:

https://baijiahao.baidu.com/s?id=1630535202760061296&wfr=spider&for=pc

获取锁

1.对象锁状态为无锁状态,Mark Word信息拷贝存储到当前线程栈桢中Lock Record(又名锁记录,创建并拷贝)里

2. CAS 操作设置Mark Word指针信息(指向自己栈帧),和 Lock Record 中指针信息

成功:获得锁对象,更新轻量级锁

失败:如果是指针指向自己则直接进入代码块,否则轻量级锁就要膨胀为重量级锁

释放锁

1.CAS操作尝试把线程中复制的Lock Record对象替换当前的Mark Word

成功: 同步完成

失败:释放锁的同时,唤醒被挂起的线程(因为已升级为重量级锁)

重量级锁

获取锁

自旋次数超过JVM预期上限,竞争的线程就会把锁对象的Mark Word指向重锁,然后所有的竞争线程放弃自旋,逐个插入到monitor对象里的一个队列尾部,进入阻塞状态

 

 

 

synchronize 关键字是用于实现线程同步的一种机制,其原理是通过在代码块或方法上加锁,来确保多个线程在执行该代码段时的互斥性。其实现原理如下: 1. 锁对象:synchronize 使用的锁对象可以是任意对象。当一个线程进入 synchronized 代码块时,它会尝试获取锁;如果锁没有被其他线程占用,则该线程获取锁,否则该线程将进入阻塞状态,直到锁被释放。 2. 对象监视器:在 Java 对象的内部数据结构中,每个对象都有一个关联的对象监视器。对象监视器负责管理锁的获取和释放,以及线程在对象上的等待和唤醒操作。当一个线程成功获取锁时,对象监视器会记录该线程的标识,并将对象的锁计数器加一。同时,其他线程在尝试获取锁时,将进入对象的等待队列,等待锁的释放。 3. 原子性操作:synchronize 关键字使得一些复合操作具有原子性。即当一个线程执行 synchronized 代码块时,其他线程无法同时进入该代码块,保证了多个线程对共享数据的同步访问。这样可以避免出现并发访问共享资源导致的数据不一致性和线程安全问题。 总之,synchronize 实现线程同步的原理是通过加锁和对象监视器来实现的。当多个线程竞争同一个锁时,只有一个线程能够获得锁,并执行 synchronized 代码块,其他线程将进入阻塞状态,直到锁被释放。这样就确保了共享数据的安全访问和操作的原子性,避免了多线程并发执行导致的数据不一致性问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值