锁的膨胀过程
当一个偏向锁被初始化出来以后,没有线程持有该锁的时候,这个锁可以被称为存在一种可偏向状态,当有一个线程持有该锁的时候,这个锁就偏向于这个
线程,当线程将锁释放以后,该锁还将继续保留该线程的信息,也就是这个把锁继续偏心/偏向于该线程
当禁止偏向锁延迟加载的时候,JVM遇到同步代码块,就会判断该锁是否可偏向,如果可以就是偏向锁,如果不可以就升级为轻量级锁。
计算过hashCode后不能成为偏向锁。偏向锁中的hashCode哪里去了?
多线程交替执行{
1.线程死亡 当该锁为偏向锁时,第二个线程获取该锁会膨胀为轻量级锁,膨胀为轻量级锁的时候,必须要撤销偏向锁,然后通过CAS操作升级为轻量锁
2.线程存活 当该锁为偏向锁时,第二个线程获取该锁会膨胀为轻量级锁,该锁为轻量锁时锁状态将继续保持轻量级锁,不会膨胀为重量级锁
}
上面的多线程交替执行表明偏向锁不可以重新偏向
批量重偏向
当一个线程t1创建了某个类的多个实例,并且用这些实例去当作锁对代码块进行加密,另一个线程对t2对t1创建的多对象同样进行加锁操作,
当t2对这个类的实例加锁到一定次数以后,t2对类的实例加锁次数阈值为20,达到20次,这些对象的状态就会批量的重新偏向t2。原因是t2
线程不停对这些类的实例进行加锁,通过cas操作膨胀为轻量锁,撤销锁,当撤销的次数达到一定次数后,jvm认为这个类的对象有问题,会把
这些类的实例批量撤销,批量重偏向.否则会导致偏向锁失去他的意义。有时候阈值不到20的时候,也会出现批量重偏向,原因同‘重偏向问题’
当没有禁止偏向锁延迟时,如果一个对象在加载偏向锁之前被初始化,那么这个对象只能时一个轻量级锁,不可能称为一个偏向锁
重偏向问题:有时候单个锁在会表现出可以重偏向的现象。原因是,两个线程t1,t2交替执行,JVM会给t1、t2分配一个线程ID,t1执行完后,t1死亡,t2初始化,
JVM分配给t2的线程ID与t1的线程ID相同,而t1执行完后锁中记录的线程信息没有被修改,这时t2执行时,JVM发现锁中的线程偏向信息同t1相同,这时候
就会出现t2用这把锁进行同步的时候,这把锁依然还是偏向锁。
为什么不单个重偏向?没有意义,如果单个重偏向,跟轻量级锁是相同的,每次都进行cas操作
批量撤销
当一批对象(同一个类的实例)被创建,并有一个线程使用了这批对象作为锁,在禁止偏向锁延迟加载时,这批对象在加锁完成后会成为偏向锁
第二个线程再去使用这批对象作为锁时,会进行锁的撤销成为轻量级锁,当达到20次时,将会批量重偏向这批对象偏向t2,第三个线程也来访问这批对象,
并使用这批对象作为锁,也会进行锁的撤销,升级为轻量级锁,当撤销的阈值达到40次时,JVM会认为这个类出现了严重的问题,会将这个类实例化的那批
对象进行批量撤销。然后全部改为轻量级锁。