zoukankan      html  css  js  c++  java
  • 锁优化的手段总结

    避免死锁

    死锁出现的四要素:

    • 互斥条件:进程对于所分配到的资源具有排它性,即一个资源只能被一个进程占用,直到被该进程释放;
    • 请求与保持条件:一个进程因请求被占用资源而发生阻塞时,对已获得的资源保持不放
    • 不可中条件:任何一个资源在没被该进程释放之前,任何其他进程都无法对他剥夺占用
    • 循环等待条件:当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞。

    减小锁的持有时间

    减小锁的持有时间有助于降低锁冲突的可能性,进而提升系统的并发能力。举例:synchronized 同步方法块,而不是整个方法。

    减小锁粒度

    所谓的减少锁粒度,就是指缩小锁定对象的范围,从而减少锁冲突的可能性,进而提高系统的并发能力。

    举例:ConcurentHashmap 中使用分段锁提高 put() 操作的并发能力,默认情况下 ConcurentHashmap 有16个段,理想情况下,它可以同时接受16个线程同时插入。

    减小锁引入的问题:当需要获取全局锁时,其消耗的资源会比较多。如 ConcurentHashmap 中的 size() 方法需要同时获取所有段的锁方能顺利实施(当然首先会使用无锁方式获取,失败时采用加锁方式获取)。

    实现锁分离

    根据读写操作功能的不同,进行有效的锁分离。如分别使用读锁和写锁,读锁之间是相容的,即对象可以持有多个读锁;对象对写锁的占用是独占式的,只有在对象没有锁的情况下才能获取对象的写锁。

    举例:LinkedBlockingQueue

    在 LinkedBlockingQueue 的实现中,take()和put()函数分别从队列中取得数据和往队列中增加数据,JDK使用了两把不同的锁分离了这个两个操作,使得两者在真正意义上成为可并发的操作。

    重入锁和内部锁

    重入锁比内部锁功能更强大,但内部锁使用更简单。JDK1.7后两者之间的性能已经差不了太多了,且内部锁将会是JDK以后优化的重点,所以建议优先使用内部锁。

    锁粗化

    虚拟机在遇到一连串连续对同一锁不断请求和释放的操作时,会把所有的锁操作整合成对锁的一次请求,从而减少对锁的请求同步数,这个操作叫做锁的粗化。

    public void demo(){
        synchronized(lock){
            //do something
        }
        //其他非同步操作
        synchronized(lock){
            //do something
        }
    }
    

    锁粗化后:

    public void demo(){
        synchronized(lock){
            //do something
            //其他非同步操作
        }
    }
    

    又如:循环中的加锁操作(循环体执行很快),应对整个循环加锁,可降低锁的请求。

    使用原子操作类

    使用java.util.concurrent.atomic下的原子操作类,替换有锁的操作,原子操作类的基础是CAS(Compare And Swap),该操作比基于锁的方式拥有更优越的性能,大部分的线程处理器都已经支持原子化的CAS指令。

    JVM层面

    自旋锁(Spinning Lock)

    锁的等待只需要很短的时间,这段时间可能比线程挂起并恢复的时间还要短,因此JVM引入了自旋锁。

    自旋锁可以使线程没有取得锁时,不被挂起,而转去执行一个空循环,在若干个空循环后,线程如果获得了锁,则继续执行,若线程依然没有获得锁,才会被挂起,避免用户线程和内核的切换的消耗。

    在JVM中使用 -XX:UseSpinning 参数来开启自旋锁,使用 -XX:PreBlockSpin 来设置自旋锁的等待次数。

    锁消除(Lock Elimination)

    通过对上下文的扫描,去除不可能存在共享资源竞争的锁,节省毫无意义的请求锁时间。

    举例:StringBuffer、Vector这些同步类用于了没有多线程竞争的场合。

    锁偏向(Biased Lock)

    如果程序没有竞争,则取消之前已经获取锁的线程同步操作。也就是说,若某一锁被线程获取后,便进入偏向模式,当线程再次请求这个锁,无需在进行相关的同步操作,如果在此之间有其他线程进行了锁请求,则锁退出偏向模式。

    偏向锁在锁竞争激烈的场合没有优化效果,因为大量的竞争会导致持有锁的进程不停地切换,锁也很难一直保持在偏向模式,使用 -XX:-UseBiasedLocking=false 禁用偏向锁。

  • 相关阅读:
    数与bit
    ARM汇编优化1
    一 *(a+1)与*(&a+1)
    二 *(a+1)多维数组
    三 二维数组取址
    四 sizeof(a)
    永恒之蓝及WannaCry分析
    github使用记录
    三种页面置换算法的C++模拟
    opencv检测图像直线
  • 原文地址:https://www.cnblogs.com/senlinyang/p/8744848.html
Copyright © 2011-2022 走看看