锁优化
⾃旋锁与⾃适应锁
⾃旋锁:为了减少线程阻塞切换等待,让线程执⾏⼀个忙循环(⾃旋),看看前⼀个线程是否能很快的释放锁,(默认是关闭)
⾃适应锁就是优化后的⾃旋锁,他的⾃旋次数是根据前⼀个锁的⾃选时间和调⽤者的状态来决定
锁消除
即时编译器对代码的优化,在不可能存在共享资源的锁进⾏消除
锁粗化
如果有⼀串零碎的代码都对同⼀个对象枷锁,将会把所同步的范围扩展(粗化)到整个操作序列的外部
轻量级锁
与重量级锁的代码写法⼀样,都是Synchronized,使⽤Synchronized时默认先加轻量级锁
轻量级锁会在线程⾥⽣成⼀个锁记录,分为锁记录地址和对象地址
当对象加上轻量级锁时,对象地址(Object Reference)指向锁对象的地址,⽽锁记录地址会与对象头 的Markwrod进⾏cas交换,交换成功则加锁成功 锁重⼊:当⾃⼰线程再次调Synchronized,则会在线程⾥增加⼀条锁记录,表示锁重⼊的计数
当解锁时,先解开锁重⼊的锁记录,对应计数减⼀,当计数为零时,则交换回来锁记录与Markword,解锁成功
【锁膨胀】 当其他线程调⽤Synchronized时,在交换时发现锁记录已经是00,则发⽣锁膨胀(由于得不到锁,只能 阻塞等待,然⽽轻量级锁没有阻塞队列⼀说,只能成为重量级锁,进⼊阻塞队列等待)
线程进⼊重量级锁的EntryList等待,Owner指向正在锁状态的轻量级锁线程,⽽对象中的Markword位指 向Monitor的地址,解锁⽅式也随之改为重量级锁的解锁⽅式
偏向锁
当发⽣锁重⼊时,轻量级锁每次都会进⾏CAS交换,影响性能。在JAVA6引⼊了偏向锁,对象头的
MarkWord中后两位为锁状态,⽽倒三位,则是偏向锁。1表示开启,0表示关闭
*偏向锁与轻量级锁⼤致差不多,即只在第⼀次将线程ID和MarkWord交换,表示锁偏向该线程,下⼀次 访问时,只检查锁是不是偏向⾃⼰,如果是就说明没有竞争,直接获得锁
*偏向锁默认是开启的,即MarkWord后三位是101
【批量重偏向】 当不是偏向的线程访问对象时,锁会进⾏撤销,然⽽撤销锁会影响性能 当撤销次数达到20次的时候,会进⾏批量重偏向,批量的将线程偏向调⽤次数多的线程
【批量撤销】 当撤销次数达到40次,则会进⾏锁消除,即将MarkWord后三位变成001,关闭偏向锁