开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情
1.偏向锁使用的前提:
至少JDK1.6 版本且开启了偏向锁配置
偏向锁在Java 6和Java 7里是默认启用的,但是它在应用程序启动几秒钟之后才激活,如有必要可以使用JVM参数来关闭延迟:-XX:BiasedLockingStartupDelay=0。如果你确定应用程序里所有的锁通常情况下处于竞争状态,可以通过JVM参数关闭偏向锁:-XX:-UseBiasedLocking=false,那么程序默认会进入轻量级锁状态。
被加锁的对象,没有真正、或者隐式的调用父类 Object 里边的hashcode方法
这句话意思是没有主动调用例如使用一个对象的hashCode()方法,或者调用map.put(K,V)方法把对象放进去,因为map.put(K,V)方法源码里会调用hashCode()方法。
2.对于以上两点,我们举例子来说明:
示例代码如下:
public class SyncLockFlag {
static MyObject myobject = new MyObject();
public static void main(String[] args) throws InterruptedException {
System.out.println("=====================未偏向线程的偏向锁============================");
System.out.println(ClassLayout.parseInstance(myobject).toPrintable());
//myobject.hashCode();
//HashMap map = new HashMap();
//map.put(myobject,""); //隐式的调用了hashcode方法
synchronized (myobject) {
System.out.println("=====================偏向锁============================");
System.out.println(ClassLayout.parseInstance(myobject).toPrintable());
}
}
static class MyObject{
}
}
执行效果如下所示:
我们可以根据红色箭头看到刚开始是无锁状态,下面为什么加完锁之后成了轻量级锁了呢? 因为我们没有使用 -XX:BiasedLockingStartupDelay=0这个参数,这个参数是立即开启偏向锁,我们进行如下的配置,在VM options中添加参数即可:
我们可以看到效果如下:
这里我们需要注意:
当我们开启了偏向锁,并且没有延迟开启的时候,新创建的对象的mark word 默认就是偏向锁状态的markword。
只不过这个时候,因为没有现成争抢,除了我们的锁标志为和是否为偏向锁标志位,其他的位数都是0。
当我们真正加锁后,markword中会记录线程id等信息。
如果此时放开代码中的hashMap注释,此时相当于隐形调用hashCode方法,结果如下图:
我们可以看到,刚开始依旧是偏向锁,后面变成了轻量级锁,为什么呢?
如果一旦调用了object的hashcode方法,那么我们的对象头里边就有真正的hashcode值了,如果偏向锁来进行markword的替换,至少要提供一个保存hashcode的地方吧?可惜的是,偏向锁并没有地方进行markword的保存,只有轻量级锁才会有“displace mark word”