• 多线程学习------07锁的优化及注意事项


    一、有助于提高锁性能的几点建议

    1 减少锁持有时间

    对于使用锁进行并发控制的应用程序来说,**如果单个线程特有锁的时间过长,会导致锁的竞争更加激烈,会影响系统的性能.**在程序中 需要尽可能减少线程对锁的持有时间,如下面代码:

    2 减小锁的粒度

    • 一个锁保护的共享数据的数量大小称为锁的粒度. 如果一个锁保护的共享数据的数量大就称该锁的粒度粗,否则称该锁的粒度细.锁的粒度过粗会导致线程在申请锁时需要进行不必要的等待.减少锁粒度是一种削弱多线程锁竞争的一种手段,可以提高系统的并发性
    • 在JDK7前,java.util.concurrent.ConcurrentHashMap类采用分段锁协议,可以提高程序的并发性

    3 使用读写分离锁代替独占锁

    • 使用ReadWriteLock读写分离锁可以提高系统性能, 使用读写分离 锁也是减小锁粒度的一种特殊情况. 第二条建议是能分割数据结构 实现减小锁的粒度,那么读写锁是对系统功能点的分割.
    • 在多数情况下都允许多个线程同时读,在写的使用采用独占锁,在 读多写少的情况下,使用读写锁可以大大提高系统的并发能力

    二、JVM 对锁的优化

    1 锁偏向

    • 锁偏向是一种针对加锁操作的优化,如果一个线程获得了锁,那么锁就进入偏向模式, 当这个线程再次请求锁时,无须再做任何同步操作,这样可以节省有关锁申请的时间,提高了程序的性能.

    • 锁偏向在没有锁竞争的场合可以有较好的优化效果,对于锁竞争比较激烈的场景,效果不佳, 锁竞争激烈的情况下可能是每次都是不同的线程来请求锁,这时偏向模式失效

    2 轻量级锁

    • 如果锁偏向失败,JVM 不会立即挂起线程,还会使用一种称为轻量级锁的优化手段. 会将对象的头部作为指针,指向持有锁的线程堆栈内部, 来判断一个线程是否持有对象锁. 如果线程获得轻量级锁成功, 就进入临界区. 如果获得轻量级锁失败,表示其他线程抢到了锁,那么 当前线程的锁的请求就膨胀为/重量级锁/.当前线程就转到阻塞队列中 变为阻塞状态

    • 偏向锁,轻量级锁都是乐观锁,重量级锁是悲观锁

    • /一个对象刚开始实例化时,没有任何线程访问它,它是可偏向的,即它认为只可能有一个线程来访问它,所以当第一个线程来访问它的时候,它会偏向这个线程. 偏向第一个线程,这个线程在修改对象头成为偏向锁时使用 CAS 操作,将对象头中 ThreadId 改成自己的 ID,之后再访 问这个对象时,只需要对比 ID 即可. 一旦有第二个线程访问该对象,因为偏向锁不会主动释放,所以第二个线程可以查看对象的偏向状态,当第二个线程访问对象时,表示在这个对象上已经存在竞争了,检查原来持有对象锁的线程是否存活,如果挂了则将对象变为无锁状态,然后重新偏向新的线程; 如果原来的线程依然存活,则马上执行原来线程的栈,检查该对象的使用情况,如果仍然需要偏向锁,则偏向锁升级为轻量级锁./

    • /轻量级锁认为竞争存在,但是竞争的程度很轻,一般两个线程对同 一个锁的操作会错开,或者稍微等待一下(自旋)另外一个线程就会释放锁. 当自旋超过一定次数,或者一个线程持有锁,一个线程在自旋,又来第三个线程访问时, 轻量级锁会膨胀为重量级锁, 重量级锁除了持有锁的线程外,其他的线程都阻塞./

    • 自旋锁(spinlock)是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。

  • 相关阅读:
    解决transform带来的z-index失效问题
    Docker-desktop(Docker桌面版)——入门篇
    VMWARE安装Ubuntu24.04桌面版的问题
    用Jmeter进行压测详解
    JAVA学习(5)-全网最详细~
    成都易佰特的坑——E103-W06
    七、【React-Router6】路由传参 之 search
    ES6 入门教程 10 对象的扩展 10.6 对象的扩展运算符
    我帮厂商找BUG系列之华大(小华)HC32F460——PWM输出占空比错误与解决方案
    R3F(React Three Fiber)经验篇
  • 原文地址:https://blog.csdn.net/qq_44818449/article/details/126089445