java中每个对象都可作为锁,锁有四种级别,按照量级从轻到重分为:无锁、偏向锁、轻量级锁、重量级锁。每个对象一开始都是无锁的,随着线程间争夺锁,越激烈,锁的级别越高,并且锁只能升级不能降级。
一、java对象头
锁的实现机制与java对象头息息相关,锁的所有信息,都记录在java的对象头中。用2字(32位JVM中1字=32bit=4baye)存储对象头,如果是数组类型使用3字存储(还需存储数组长度)。对象头中记录了hash值、GC年龄、锁的状态、线程拥有者、类元数据的指针。
二、偏向锁
在实际应用运行过程中发现,“锁总是同一个线程持有,很少发生竞争”,也就是说锁总是被第一个占用他的线程拥有,这个线程就是锁的偏向线程。
那么只需要在锁第一次被拥有的时候,记录下偏向线程ID。这样偏向线程就一直持有着锁,直到竞争发生才释放锁。以后每次同步,检查锁的偏向线程ID与当前线程ID是否一致,如果一致直接进入同步,退出同步也,无需每次加锁解锁都去CAS更新对象头,如果不一致意味着发生了竞争,锁已经不是总是偏向于同一个线程了,这时候需要锁膨胀为轻量级锁,才能保证线程间公平竞争锁。
1.加锁
偏向锁加锁发生在偏向线程第一次进入同步块时,CAS原子操作尝试更新对象的Mark Word(偏向锁标志位为"1",记录偏向线程的ID)。
2.撤销偏向锁
当有另一个线程来竞争锁的时候,就不能再使用偏向锁了,要膨胀为轻量级锁。
竞争线程尝试CAS更新对象头失败,会等待到全局安全点(此时不会执行任何代码)撤销偏向锁。
三、轻量级锁
轻量锁与偏向锁不同的是:
- 轻量级锁每次退出同步块都需要释放锁,而偏向锁是在竞争发生时才释放锁
- 每次进入退出同步块都需要CAS更新对象头
- 争夺轻量级锁失败时,自旋尝试抢占锁
可以看到轻量锁适合在竞争情况下使用,其自旋锁可以保证响应速度快,但自旋操作会占用CPU,所以一些计算时间长的操作不适合使用轻量级锁。
1.加锁
加锁过程和偏向锁加锁差不多,也是CAS修改对象头,只是修改的内容不同。
- 在MarkWord中保存当前线程的指针
- 修改锁标识位为“00”
采用CAS操作的原因是,不想在加锁解锁上再加同步
如果对象处于无锁状态(偏向锁标志位为"0",锁标志位为"01"),会在线程的栈中开辟个锁记录空间(Lock Record),将Mark Word拷贝一份到Lock Record中,称为Displaced Mark Word,在Lock Record中保存对象头的指针(owner)。
接下来CAS更新MarkWord,将MarkWord指向当前线程,owner指向MarkWord,如果失败了,则意味着出现了另一个线程竞争锁,此时需要锁膨胀为轻量级锁。
2.解锁
用CAS操作锁置为无锁状态(偏向锁位为"0",锁标识位为"01"),若CAS操作失败则是出现了竞争,锁已膨胀为重量级锁了,此时需要释放锁(持有重量级锁线程的指针位为"0",锁标识位为"10")并唤醒重量锁的线程。
3.膨胀为重量级锁
当竞争线程尝试占用轻量级锁失败多次之后,轻量级锁就会膨胀为重量级锁,重量级线程指针指向竞争线程,竞争线程也会阻塞,等待轻量级线程释放锁后唤醒他。
三、重量级锁
重量级锁的加锁、解锁过程和轻量级锁差不多,区别是:竞争失败后,线程阻塞,释放锁后,唤醒阻塞的线程,不使用自旋锁,不会那么消耗CPU,所以重量级锁适合用在同步块执行时间长的情况下。
四、参考
- 《Java并发编程的艺术》
- 《轻量级锁与偏向锁》
- 《Synchronized下的三种锁:偏向锁 轻量锁 重量锁 理解》
- 《JAVA锁的膨胀过程和优化》
相关推荐
很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,本文详细介绍了Java SE1.6中为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁,...
在本文中小编给的大家整理了关于Java锁的升级策略 偏向锁 轻量级锁 重量级锁的相关知识点内容,需要的朋友们参考下。
由于对象头的信息是与对象自身定义的数据没有关系的额外存储成本,因此考虑到JVM的空间效率,Mark Word 被设计成为一个非固定的数据结构,以便存储更多有效的数据,它会根据对象本身的状态复用自己的存储空间,如32...
NULL 博文链接:https://eleopard.iteye.com/blog/1746671
一文读懂原子操作、内存屏障、锁(偏向锁、轻量级锁、重量级锁、自旋锁)、Disruptor、Go Context之上半部分.doc
【Java面试】为什么引入偏向锁、轻量级锁,介绍下升级流程.doc
锁状态(是否偏向锁)(锁标志位)无锁对象 hashCode对象分代年龄偏向锁对象分代年龄轻量级锁指向栈中锁记录的指针重量级锁指向重量级锁的指针GC 标记锁状态优
* [轻量级锁](#轻量级锁) * [自旋锁](#自旋锁) * [自适应自旋锁](#自适应自旋锁) * [锁消除](#锁消除) * [锁粗化](#锁粗化) * [死锁](#死锁) * [如何避免死锁?](#如何避免死锁) * [volatile](#volatile) * ...
偏向锁理论太抽象,实战了解下偏向锁如何发生以及如何升级【实战篇】.doc
偏向锁、轻量级锁和重量级锁不同的地方在于不是通过信号量机制(强制阻塞)而是通过自旋CAS实现互斥访问的,避免了强制阻塞时用户态与核心态之间切换带来的开销(系统调用),这里的开销主要是保存用户态的上下文...
使用java模拟synchronzed的过程,模拟从无锁->偏向锁->轻量级锁->重量级锁->挂起->唤醒->继续抢锁,再模拟了各阶段的锁释放。(此代码不能运行,因为很多c++中的机制在java中不能实现)此代码仅用于学习synchronized的...
从思维导图的角度将 Java 关键字 Synchronized进行分析整理,含盖CAS、偏向锁、轻量级锁、重量级锁及锁升级,同时附加了常见问题整理
案例1(无锁,不可偏向状态) import org.openjdk.jol.info.ClassLayout; public class Demo1 { public static void main(String[] args) throws InterruptedException { A a = new A(); /// 理论上说这里应该是...
**为什么有自旋锁还需要重量级锁?** > 自旋是消耗CPU资源的,如果锁的时间长,或者自旋线程多,CPU会被大量消耗 > > 重量级锁有等待队列,所有拿不到锁的进入等待队列,不需要消耗CPU资源 **偏向锁是否一定比自旋...
股指期权研究-中银国际期货-金融期权研究:情绪偏向乐观,IV小幅上升.pdf
所以为了在一定程度上减少获得锁和释放锁带来的性能消耗,在 jdk6 之后便引入了“偏向锁”和“轻量级锁”,所以总共有4种锁状态,级别由低到高依次为:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。...
偏向于软件工程师的面试资料整理。 推荐资料 :open_book: | 书籍 | :open_book: | 书籍 | :memo: | 文章 | (:thumbs_up:) 笔试: 面试: :memo: | 文章 | (:thumbs_up:) 技术面试必备基础知识、Leetcode 题解、Java...
偏向锁:sparkles:Java IOJVM垃圾收集CMSG1ZGC元空间字节码操作JVM 调优分布式分布式算法PaxosRaftBFT分布式锁Redis 分布式锁分布式事务MySQL查询语句基本原理innodb 存储引擎:sparkles:缓存Redis底层原理开源框架...
1.偏向锁 2.轻量级锁 3.锁的优缺点对比
偏向锁、轻量级锁、重量级锁 1.10 锁的公平性 1.11 线程组 2 多线程基本实现 2.1 多线程实现 Interface Runnable Callable Future ExecutorService Class Thread FutureTask FutureTask 获取线程执行结果的原理:以 ...