偏向锁、轻量级锁、重量级锁和锁的升级过程

如何实现多线程

我们在使用多线程访问资源时,为了防止冲突,我们一般会怎么做呢?
首先会想到,用synchronized呗.
那synchronized原理是啥呢?加锁呗.
这时候如果是面试的话,面试官就要开始拷打了:synchronized做了哪些优化?
直接搬结论,java1.6后,java的开发人员针对锁机制进行了优化,增加了偏向锁、轻量级锁.

锁的介绍

啥是锁

不是哥么,你锁来锁去,咩是锁啊?
锁就是一个对象,就举synchronized的例子,修饰普通方法的时候,锁的就是实例对象,修饰静态方法的时候,锁的是class对象,修饰代码块的时候,锁的是自定义对象

对象的组成部分

你说是对象就是对象,那我普通对象和锁对象有啥区别啊?
还真有~

首先我们先来看,对象有哪些组成部分:对象头、实例数据、对齐填充字节
其中对象头又由Mark Word(对象运行时的数据)、Klass Pointer(指向对象类型的指针)、数组长度(对象不为数组就没有这一部分)

判断一个对象 是不是锁、是谁的锁 的信息就存放在Mark Word里面,具体而言长啥样?
上图
在这里插入图片描述
注意哈,这里的这个图不是整个对象头,而是说每种情况的对象头各自的组成部分,那你可能要问,无锁态有hashCode,分代年龄这些东西,怎么偏向锁、轻量级锁、重量级锁有的就没了?
诶,问到点上了.
简而言之,就是偏向锁、轻量级锁就是没有hashcode,想有hashcode的话,会升级为重量级锁,将hashcode存储在ObjectMonitor里面
那分代年龄呢,轻量级锁会存储在lock record里面,重量级锁的分代年龄在ObjectMonitor里面

锁的升级过程

直接速通

偏向锁

  • 当线程第一次访问共享资源时,使用CAS操作,将自己的线程id,赋值给Mark Word中,同时修改Mark Word里面的偏向锁标志位为1
  • 后续线程访问资源时,只需要判断(不需要使用CAS操作)对象头中的线程id和自己的线程id是否一致,一致就OK. 否则,使用CAS修改偏向锁,或者撤销偏向锁,将锁升级为轻量级锁

轻量级锁

  • 首次升级为轻量级锁时:先在线程自己的栈帧中创建锁记录,把Mark Word的信息复制到锁记录中,将锁记录中的owner指针指向当前线程,修改Mark Word为锁记录的指针
  • 而后,每次线程访问资源,都使用CAS操作试图修改owner指针指向自己,若成功则可访问资源,否则会自旋重试,失败到达一定次数(默认10次),会升级为重量级锁

重量级锁

  • 首次升级为重量级锁时:将指向Monitor的指针赋值给Mark Word,同时修改锁标志位为10
  • 而后每次回去查看Monitor的owner是否为自己(可重入),若是则可以获取锁并访问资源,否则说明有其他线程持有锁,该线程阻塞

重量级锁的底层

  • 底层是一个Monitor,和对象绑定,里面有三个重要部分:Owner、Entry List、Wait Set
  • Owner:当前持有锁的线程,有且仅有一个
  • Entry List:因获取锁失败而阻塞的线程
  • Wait Set:调用了wait方法处于等待状态的线程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值