自适应自旋锁:(java6引入,jvm对锁的预测会愈来愈精准,jvm也会愈来愈聪明)java
- 自选次数再也不固定
- 由前一次在同一个锁上的自旋时间及锁拥有者的状态来决定(若是在同一个锁对象上自旋等待刚刚成功获取过锁而且持有锁的线程正在运行中,jvm会认为该锁自旋获取到锁的可能性很大,会自动增长等待时间,相反jvm 若是可能性很小会省掉自旋过程,避免浪费)
锁消除:jvm的另外一种锁优化,更完全的优化多线程
- JIT编译时,对运行上下文进行扫描,去除不可能存在的竞争的锁,消除毫无心义的锁

锁粗化:另外一种极端,锁消除的做用在尽可能小的范围使用锁,而锁粗化则相反,扩大加锁范围。好比加锁出如今循环体中,每次循环都要执行加锁解锁的,如此频繁操做比较消耗性能jvm
synchronized的四种状态性能
- 无锁
- 偏向锁
- 轻量级锁
- 重量级锁
锁膨胀方向:无锁->偏向锁->轻量级锁->重量级锁,synchronized会随着竞争状况逐渐升级,如出现了闲置的monitor也会出现锁降级优化
偏向锁:减小同一个线程获取锁的代价.net
- 大多数状况下,锁不存在多线程竞争,老是由同一个线程屡次得到
ps:核心思想就是若是一个线程得到了锁,那么锁就进入偏向模式,此时MarkWord的结构也变成偏向锁结构,当该线程再次请求锁时,无需再作任何同步操做,即获取锁的过程只须要检查MarkWord的锁标记位为偏向锁以及当前线程ID等于MarkWord的ThreadID便可,这样就省去了大量有关锁申请的操做线程
不适合用于锁竞争比较激烈的多线程场合指针
轻量级锁:对象
轻量级锁是由偏向锁升级而来的,偏向锁运行再一个线程进入同步块的状况下,当第二个线程加入锁争用的时候,偏向锁就会升级为轻量级锁blog
适用场景:线程交替执行的同步块
若存在同一时间访问同一锁的状况,就会致使轻量级锁膨胀为重量级锁
轻量级锁的加锁过程:
此图来自https://blog.csdn.net/zqz_zqz
- 在代码进入同步块的时候,若是同步对象锁状态为无锁状态(锁标志位为“01”状态,是否为偏向锁为“0”),虚拟机首先将在当前线程的栈帧中创建一个名为锁记录(Lock Record)的空间(线程私有的栈帧里),用于存储锁对象目前的Mark Word的拷贝(对象是存在堆中的,因此对象的MarkWord也再堆中),官方称之为 Displaced Mark Word。
- 拷贝对象头中的Mark Word复制到锁记录中;
- 拷贝成功后,虚拟机将使用CAS操做尝试将对象的Mark Word更新为指向Lock Record的指针,并将Lock record里的owner指针指向object mark word。若是更新成功,则执行步骤4,不然执行步骤5。
- 若是这个更新动做成功了,那么这个线程就拥有了该对象的锁,而且对象Mark Word的锁标志位设置为“00”,即表示此对象处于轻量级锁定状态,这时候线程堆栈与对象头的状态如图所示。
- 若是这个更新操做失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,若是是就说明当前线程已经拥有了这个对象的锁,那就能够直接进入同步块继续执行。不然说明多个线程竞争锁,轻量级锁就要膨胀为重量级锁,锁标志的状态值变为“10”,Mark Word中存储的就是指向重量级锁(互斥量)的指针,后面等待锁的线程也要进入阻塞状态。 而当前线程便尝试使用自旋来获取锁,自旋就是为了避免让线程阻塞,而采用循环去获取锁的过程。

锁的内存语义
- 当线程释放锁时,java内存模型会把该线程对应的本地内存中的共享变量刷新到主内存中
- 当线程获取锁时,java内存模型会把该线程对应的本地内存置为无效,从而使得被监视器保护的临界区代码必须从主内存中读取共享变量
总结:
