前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面试synchronized你还会怕吗?

面试synchronized你还会怕吗?

作者头像
小土豆Yuki
发布2020-06-15 17:49:54
4750
发布2020-06-15 17:49:54
举报
文章被收录于专栏:洁癖是一只狗

01synchronized作用

synchronized提供一中互斥机制,也就是同一时刻,只能有一个线程访问同步资源。

02

jvm指令分析

先来看一个类,看一下他的JVM指令,使用javap反汇编,看一小段jvm指令

能够看出synchronized是基于monitor enter 和monitor exit 实现互斥的,因此我们介绍一下他们是如何实现的。

1.Monitorenter

每一个对象与一个monitor,一个monitor的lock的锁只能被一个线程同一时刻获得,当一个线程获得与对象monitor的所有权是会发生的几件事情

1.monitor的计数器为0时,说明没有线程获得mmonitor 的lock,某个线程在获得lock计数器就会加.

2.该线程已经获得monitor在次重入获得,技术器再次加 一.

3.当另外一个线程尝试获得monitor的lock,将会被挂起,知道monitor的计数 器为0.才能再次尝试获得monitor的所有权.

2.monitorexit

想要释放锁,前提是该线程获得monitor的lock,就是要把monitor的计数器减一,就会释放锁,其他挂起的线程将会尝试获得monitor的所有权.

注意

1.monitor关联的对象不能为空,monitor将无从谈起.

2.synchronized 作用太大,代表性能越差.

3.不停的monitor企图锁相同的对象起不到互斥的作用.

4.多个锁交叉会导致死锁 .

接着我们在介绍一下两个特别的monitor ,this monitor 和class monitor,还是一样先看一段代码。

menthod1,method2,method3是一样都是this monitor ,metnod4,method5,method6也是一样的是class monitor,我们再反汇编一下,看看其中一段指令。

我们看看method2和method3有什么不一样,我们看到标红的位置,method2没有monitor enter和monitor exit,而发现有一个关键此ACC_SYNCHRONIZED,其实这是因为JVM使用ACC_SYNCHRONIZED访问一个方法是够是同步方法,当方法调用时,调用指令将会检查方法是哦股被设置成ACC_SYNCHRONIZED访问标志,如果有该标志,执行线程将现持有Monitor对象,然后执行方法,在该方法运行期间,其他线程无法获得Monitor对象,执行完方法后,在释放Monitor对象。

03

synchronized优化

由于Monitor是依赖于底层的操作系统实现,所以有用户态和内核态的切换,性能会差一些,因此就引入了偏向锁,轻量级锁,重量级锁进行优化;

1.偏向锁.

由于很多情况下,不仅不存在线程净增,而且总是由同一线程多次获得,因为每次操作都会发生用户态和内核态的切换

为了减少获取锁的代价,引入了偏向锁;

2.轻量级锁.

但是当多有一定的线程竞争就会升级为轻量级锁,轻量级 锁用于线程交替执行的场景,由于大多数线程持有锁是很短的时间,所以轻量级锁就会自旋重新获得锁,不然线程阻塞也是一种性能损失(如果锁竞争激烈也会占用cpu资源,反而会影响开销);

3.重量级锁.

在高并发场景下最终会是会升级到重量级锁;

他们升级的流程大体是:

1.检查MarkWord是否存在线程的id;

2.如果没有存储线程id,获得偏向锁,将MarkWord中的线程ID设置成自己;

3.如果有存储线程id,线程使用CAS操作把这个锁的线程ID记录在对象Mark Word之中,同时置是否偏向标志位1.(以后该线程在进入和退出同步快是不需要进行CAS操作来加锁和解锁,只需要测试一下对象头的Mark word里面是否存储着只想当前线程的偏向锁,如果成功表示线程已经获得了锁);

4.如果CAS操作失败,则当达到全局安全点时,获得偏向锁的线程被挂起,膨胀为轻量级锁,同时撤销偏向锁且设置是否偏向标志为0;

5.当有线程竞争这个锁,进行CAS操作,如果成功获得轻量级锁,执行同步代码

6.如果失败,通过自旋不断尝试获取锁,从而避免线程挂起阻塞.

7.如果自旋依然失败,就会升级到重量级锁,标志改成10,反之成功,继续轻量级锁;

当然还要其他的优化方式:

1.逃逸分析技术,判断同步快使用多的对象是否只能被一个线 程访问,而没 有发布到其他线程,如果是的化,就不会JIT就不会生成申请锁和释放锁的的 机器码,消除锁的使用;

2.锁的粗化,JIT把相邻的同步快使用同一个锁;

3.较少锁粒度,把锁对象分成一个数组或一个队列,减少净增 提高并行度,正 如JDK1.7实现的ConcurrrentHashMap;

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 洁癖是一只狗 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档