synchronized底层原理

1.synchronized实现原理
在这里插入图片描述

synchronized借助对象的monitor来实现,每个对象都有monitor,monitor有_owner,_count,_entryList,_waitSet等属性,当一个线程访问synchronized修饰的代码块或方法时,首先会检查_owner是否指向线程,如果指向线程则判断是否是一个线程,是则获取锁,_count+1,不是则进入_entryList等待持有线程释放锁,_waitSet是在持有锁的线程调用了wait方法时进入等待的集合。
2.编译器是如何知道这段代码或方法被synchronized修饰?
synchronized修饰同步代码块时会生成monitorenter,monitorexit指令,当执行monitorenter时就会促发上诉流程,在执行完之后或抛出异常时会执行monitorexit。
synchronized修饰方法时会生成ACC_SYNCHRONIZED标识,通过读取flags中的ACC_SYNCHRONIZED标识来促发上诉流程。
3.为什么这样的synchronized是一个重量锁?
synchronized依赖monitor来实现,monitor则通过操作系统的独占锁来实现,独占锁又被称为重量锁,而且没获得锁的线程都会阻塞,阻塞后被唤醒需要操作系统来帮忙,这就需要从用户态转换到内核态,而转换状态是需要消耗很多时间的,有可能比用户执行代码的时间还要长。
4.Java 1.6之后的synchronized优化?
在这里插入图片描述

在优化之后,synchronized锁机制是从偏向锁转换为轻量锁,再转换成重量锁。偏向锁在同一时间只能有一个线程执行,如果有两个线程竞争锁则会膨胀成轻量锁,轻量锁也就是自旋,可分为自旋锁和自适应自旋锁。自旋是会消耗cpu资源的,所以在自旋指定次数后会再次膨胀为monitor锁,monitor锁中等待的线程会暂时让出cpu资源。
5.各种锁的优缺点?
偏向锁:同一个线程进入同步区域是不需要再次加锁释放锁的,而且实现起来也是在对象头的mark word中添加了threadId,比较简单,缺点是只要有两个线程同时竞争锁,偏向锁就失效了,所以绝大多数情况下是不符合业务需求的。
轻量锁:轻量锁从自旋进化到自适应自旋,是一种乐观锁,只要持锁线程释放锁就立刻参与获得锁,在并发不是很大的情况下一般立刻就能获取锁。自旋的缺点是一直占有cpu资源,所以JVM规定在自旋10次之后会膨胀为重量锁。而自适应自旋是认为获取过锁的线程再次获取锁的概率会更大,会给获取过锁的线程更多的自旋次数,而没获取过的线程获取锁的概率就会很小,会降低没获取过锁的线程自旋次数。
重量锁:monitor锁,依靠操作系统的排他锁来实现,而monitor锁本身是靠c++实现,缺点是在线程从阻塞到唤醒过程时间很长,需要操作系统把线程从用户态转换到内核态。
6.各种锁的选择?
个人感觉偏向锁几乎没什么用,本来加锁就是在并发情况下保证数据安全的一种选择,而偏向锁只能由一个线程进入。轻量锁可能是大多数情况的选择,重量锁则是非常高并发下的选择。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值