synchronized详解

in 应用教程
关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9

synchronized详解

解释

synchronized是jvm级别的一种重量级锁,但是随着jdk对synchronized的不断优化,现在它已经变得没有我们想象的那么重了。由于synchronized使用简单,也不用手动释放锁,因此我们平时开发中用到最多的锁就是它了。

synchronized锁的三种形式

实现原理

同步代码块在编译后会在前后分别插入monitorenter和monitorexit指令,每个对象在同一时刻只会与一个monitor相关联,当线程执行到monitorenter指令时就会尝试获取对象所对应的monitor的所有权,如果这个monitor已经被其他线程获取,则需要等待锁释放。

对象头

synchronized锁是存在对象头中的。如果对象是数组类型,则虚拟机用3个字宽存储对象头,如果对象是非数组类型,则用2个字宽存储对象头。在32位虚拟机中,1字宽等于4字节,即32bit。

补充一点:Java对象保存在内存中,由三部分组成:对象头、实例数据、对齐填充字节。Java头由三部分组成:Mark Word、指向类的指针、数组长度(只有数组对象才有)。

32位jvm的Mark Word的存储结构如下

锁状态 25bit 4bit 1bit是否偏向锁 2bit锁标志位
无锁状态 对象的hashCode 对象分代年龄 0 01

Mark Word中的数据随着锁标志位的变化而变化,如下

mark

锁的升级

java1.6以后,为了减少获取锁和释放锁的性能消耗,引入了“偏向锁”和”轻量级锁“。锁的状态可以从无锁状态->偏向锁->轻量级锁->重量级锁,随着竞争情况逐渐升级,但是不能降级。

mark

偏向锁

大多数情况下,锁不仅不存在多线程竞争,而且总是由同一个线程多次获得,为了让线程获得锁的代价更低引入了偏向锁。当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解释,只需要简单地测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。如果是,则直接获得锁,执行同步块;如果不是,则使用CAS操作更改线程ID,更改成功获得锁,更改失败开始撤销偏向锁。

撤销偏向锁

偏向锁只有存在锁竞争的情况下才会释放。撤销偏向锁需要等待全局安全点(在这个时间点上没有正在执行的字节码),首先暂停偏向锁持有的线程,然后检查此线程是否活着,如果线程不处于活动状态,则转成无锁状态;如果还活着,升级为轻量级锁。下图展示了偏向锁的获得与撤销过程

mark

轻量级锁

mark

重量级锁

因为自旋会消耗CPU,为了避免无用的自旋,一旦锁升级成重量级锁,就不会再恢复到轻量级锁状态。当锁处于这个状态下,其他线程试图获取锁时,都会被阻塞住,当持有锁的线程释放锁之后会唤醒这些线程,被唤醒的线程就会进行新一轮的夺锁之争。

关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
扫一扫关注公众号添加购物返利助手,领红包
Comments are closed.

推荐使用阿里云服务器

超多优惠券

服务器最低一折,一年不到100!

朕已阅去看看