08给女朋友讲讲并发编程-轻量级锁、锁膨胀、自旋、锁消除、偏向锁

2021-01-06  本文已影响0人  XueFengDong

一、轻量级锁

在多线程条件下,虽然一个对象会有多个线程访问,但是他们访问的时间是错开的(没有竞争关系),那么可以使用轻量级锁来优化。

1.使用轻量级锁的目的

降低无实际竞争关系的情况下,直接使用重量级锁带来的性能消耗。

2.轻量级锁的使用

轻量级锁对使用者是透明的,语法仍然是synchronized.
假设有两个方法同步块,对同一个对象加锁。

static final Object object = new Object();

public static void method1(){
     synchronized(obj){
          //同步块A
          method2();
      }
}

public static void method2(){
      synchronized(obj){
        //同步块B
      }
}

二、锁膨胀

问:上述执行轻量级锁的过程中,如果cas失败了,怎么办?

三、自旋

如果持有锁的线程很快就能将锁释放,那么其余线程就不需要进入EntryList阻塞队列中等待(内核态与用户态之间的切换进入阻塞状态)。它们只需要短时间的等待(自旋),等待持有锁的线程释放锁后,即可不用进入阻塞队列直接获取锁。

四、锁消除

static int x = 0;

public void methodA(){
    x++;
};

public void methodB(){
    Object obj = new Object();
    synchronized(obj){
        x++;
    }
}

上述代码中methodA()和methodB()方法不同点是methodB()方法对局部变量对象加锁去执行++操作,理论上synchronized会影响性能,降低代码的执行效率。但是通过Benchmark对两个方法进行测试,发现两个方法的执行时间几乎没有差别。
为什么:
JVM中重要的核心模块之一 JIT即时编译器,它可以对字节码文件进一步优化,它会发现上述代码中的局部变量根本不会逃离方法的作用范围,就意味着这个对象不可能被共享,那么methodB()中的synchronized关键字也就显得没有意义了,JIT即使编译器就会将无意义的代码优化掉,也就是锁消除

-XX:-EliminateLocks

五、偏向锁

顾名思义,他会偏向第一个访问锁的线程,如果在运行过程中,同步锁只有一个线程访问,不存在别的线程来使用的情况,就会给线程加一个偏向锁。锁标记为1,没有偏向锁则为0。
如果在执行过程中,遇到了其他线程抢占锁,则会升级为轻量级锁。
JVM默认启用偏向锁,在竞争激烈的场合,偏向锁会增加系统负担。
关闭偏向锁

-XX:-UseBiasedLocking

JVM启用偏向锁时,默认会有4s的延迟。原因在于,系统刚启动时,一般数据的竞争是比较激烈的,此时启用偏向锁会降低性能。
修改偏向锁延迟时间

-XX:BiasedLockingStartupDelay=0
上一篇 下一篇

猜你喜欢

热点阅读