Java 锁优化

Java锁优化

首先解释一下,Java中,对锁的优化,主要是优化 sychronized 关键字,优化是在JVM层面,并且是在JDK5之后,因为之前 sychronized 的运行效率太低

先看看编译之后的Class文件

在JVM中,每个对象都会有一个对象头的数据Mark Word,该对象头中存储了对象的哈希码,对象分代年龄,锁标识,还有偏向模式

锁状态哈希码分代年龄偏向模式标识位
未锁定01
轻量锁定00
重量锁定10
GC标识01
偏向01

当使用 sychronized 的时候,首先就是将对象的未锁定状态改变为锁定状态,并且记录下获取锁的线程ID,因为 sychronized 是可重入的锁,所以还需记录获取锁的线程的重入次数

什么是偏向?

偏向的意思就是当没有线程竞争获取锁的时候,锁会偏向于第一个获取该锁的线程,在第一次获取锁之后,如果之后都没有其他线程想要获取锁,那么持有锁的线程以后都不需要同步,不需要同步会提高代码的执行效率,因为 sychorinzed 在获取锁的时候,是一个系统调用过程,系统调用过程就必须用自陷切换到和心态去执行,上下文切换带来的开销肯定很大,所以这是优化的第一步!

出现竞争,偏向失败,接下来怎么办?自旋,自旋优化

当出现多个线程竞争1个锁的时候,系统会放弃使用偏向锁,转而进行第二步的优化,使用自旋锁,所谓自旋锁,顾名思义,就是使用一个循环,不断的去尝试获取锁,从而避免获取不到锁的线程被阻塞,因为被阻塞会从用户态切换到和心态,有上下文切换的开销,这是一个很重的操作,而使用自旋,就不会产生上下文切换,也不会阻塞线程,但是自旋操作也有缺点,就是说当一个线程因为获取不到锁而长期自旋时,会长时间的占用CPU资源,导致CPU资源的浪费,所以自旋必须要加上一个自旋次数来控制,并且,JVM还提供了一种操作,就是自适应自旋,通过上一次在同一个锁上的自旋次数来决定下一次的自旋次数,对于某个锁,如果自旋很少成功获取到锁,那之后,有可能直接省略掉自旋过程,直接阻塞线程

轻量级锁和重量级锁

Lock Record :锁记录,用户存储对象当前 Mark Word 的拷贝
使用CAS尝试更改对象的Mark Word更新为指向锁记录 ,如果更新成功,那么直接进入同步块继续执行即可,如果更新失败,表示有多个线程同时在竞争该所,此时轻量级锁必须膨胀为重量级锁,也就是互斥锁,后面获取锁的线程必须要阻塞

代码优化之锁清除

Java编译器在运行时,对检测不到的共享数据竞争进行锁清除,根据逃逸分析的数据支持,判断一个代码块,在堆上的数据都不会逃逸出去而被其他线程访问到,就可以直接把其当成栈上的数据,无需加锁

代码优化之锁粗化

因为频繁的进行同步互斥会导致不必要的消耗,JVM会直接将加锁同步的范围扩大到整个操作序列,这样就只需要加1次锁即可

CAS

CompareAndSet,比较并交换,该方法是由硬件提供的一种实现原子操作的方法,原子操作是一种不可分割的指令序列,CAS使用3个参数,内存地址,旧值,需要更新的新值,当内存地址上的值和旧值一样时,就将旧值更新为新值

PS:逃逸优化后续会填坑

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值