synchronized

synchronized

1.synchronized原理:

synchronized修饰的同步代码块,使用的是monitorenter 和 monitorexit 指令,monitorenter指令指向同步代码块的开始位置,monitorexit指令则指明同步代码块的结束位置,JVM需要保证每一个monitorenter都有一个monitorexit与之相对应。任何对象都有一个monitor与之相关联,当且一个monitor被持有之后,他将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor所有权,即尝试获取对象的锁;
synchronized方法是在方法常量池中的方法表结构(method_info Structure) 中的 ACC_SYNCHRONIZED 访问标志区分一个方法是否同步方法,当方法调用时,调用指令将会 检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果被设置调用该方法的对象或该方法所属的Class在JVM的内部对象表示Klass做为锁对象。

2.synchronized jdk1.6优化:

jdk1.6对锁的实现引入了大量的优化,如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销。同时通过java对象头的markdown中是否偏向锁,锁标识来判断当前锁的状态,锁主要存在四中状态,依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,他们会随着竞争的激烈而逐渐升级。注意锁可以升级不可降级,这种策略是为了提高获得锁和释放锁的效率。

3.自旋锁、自适应自旋锁、锁粗化、锁消除场景:

自旋锁:自旋锁是是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。获取锁的线程一直处于活跃状态,如果在大多数情况下,线程持有锁的时间都不会太长,如果直接挂起操作系统层面的线程会造成资源的浪费。
自适应自旋锁:自适应意味着自旋的时间不再固定了,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定,自适应自旋解决的是“锁竞争时间不确定”的问题。
锁粗化:就是将多个连续的加锁、解锁操作连接在一起,扩展成一个范围更大的锁。在大多数情况下,在使用同步锁的时候,需要让同步块的作用范围尽可能小—仅在共享数据的实际作用域中才进行同步,这样做的目的是为了使需要同步的操作数量尽可能缩小,如果存在锁竞争,那么等待锁的线程也能尽快拿到锁。
锁消除:在有些情况下,JVM检测到不可能存在共享数据竞争,就会进行锁消除操作,锁消除可以节省毫无意义的请求锁的时间。

4.偏向锁、轻量级锁、重量级锁转换:

偏向锁转换为轻量级锁: 首先,检测Mark Word是否为可偏向状态,若为可偏向状态,则测试线程ID是否为当前线程ID,如果是则执行同步代码块,不是则通过CAS操作竞争锁,竞争成功,则将Mark Word的线程ID替换为当前线程ID,竞争失败则证明当前存在多线程竞争情况,当到达全局安全点,获得偏向锁的线程被挂起,偏向锁升级为轻量级锁,然后被阻塞在安全点的线程继续往下执行同步代码块。
轻量级锁转换为重量级锁:转变为轻量级锁后,当线程进来,判断当前对象是否处于无锁状态,若是,则JVM首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝,JVM利用CAS操作尝试将对象的Mark Word更新为指向Lock Record的指正,如果成功表示竞争到锁,则将锁标志位变成00(表示此对象处于轻量级锁状态),执行同步操作。如果当前对象不是无锁状态或者执行同步操作失败,则判断当前对象的Mark Word是否指向当前线程的栈帧,如果是则表示当前线程已经持有当前对象的锁,则直接执行同步代码块;否则只能说明该锁对象已经被其他线程抢占了,这时轻量级锁需要膨胀为重量级锁,锁标志位变成10,后面等待的线程将会进入阻塞状态

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值