• 【JavaEE】synchronized原理 -- 多线程篇(6)


    1. synchronized具体采用了哪些加锁策略?

    1. synchronized既是悲观锁, 也是乐观锁
    2. synchronized既是重量级锁, 也是轻量级锁
    3. synchronized重量锁部分是基于系统的互斥锁实现的; 轻量级锁部分是基于自旋锁实现的;
    4. synchronized是非公平锁 (不会遵守先来后到, 锁释放之后, 哪个线程拿到锁, 各凭本事)
    5. synchronized是可重入锁 (内部会记录哪个线程拿到了锁, 记录引用计数)
    6. synchronized不是读写锁

    synchronized采取自适应的加锁策略!

    2. synchronized内部实现策略(内部原理)

    代码中写了一个 synchronized之后, 这里可能会产生一系列的"自适应的过程", 锁升级(锁膨胀);

    在这里插入图片描述

    2.1 偏向锁

    • 不是真正的加锁, 而只是做了一个 “标记”, 如果有别的线程来竞争锁了, 才会真正的加锁; 如果没有别的线程竞争, 就自始至终不会真的加锁了
    • 加锁本身, 有一定开销, 能不加, 就不加, 有人来竞争了, 才会真正的加锁~

    2.2 轻量级锁与重量级锁

    • synchronized通过自旋锁的方式来实现轻量级锁
      • 我这边把锁给占了, 另一个线程就会按照自旋的方式, 来反复查询当前的状态是不是被释放了
    • 但是, 后续, 如果竞争这边锁的线程越来越多了(锁冲突更激烈了), 从轻量级锁 升级 成重量级锁
      • 轻量级锁: 这个锁操作都是比较消耗 CPU 的 如果能够比较快速的拿到锁, 多消耗点 CPU 也不亏
      • 但是随着竞争激烈, 即使前一个线程释放锁, 也不一定能拿到锁, 啥时候能拿到, 时间可能会比较久, 所以没必要一直占用CPU资源

    3. synchronized 的其它优化策略

    3.1 锁消除

    • 编译器, 会智能的判定, 当前这个代码, 是否有必要加锁
      • 如果你写了加锁, 但实际上没有必要加锁, 就会把加锁操作自动删除掉
    • 程序员也不能全指望考优化提高代码效率, 咱们自己也得发挥一些作用, 判断何时加锁, 也是咱们一个非常重要的工作

    3.2 锁的粒度

    概念

    • 加锁操作里面包含的实际要执行的代码越多, 就认为锁的粒度越大

    在这里插入图片描述

    • 有时候, 希望锁的粒度小比较好, 并发程度高
    • 有时候, 也希望锁的粒度大比较好 – 因为加锁解锁本身也有开销

    JVM 对锁的粒度的优化

    在这里插入图片描述

    • 实际开发过程中, 使用细粒度锁, 是期望释放锁的时候其他线程能使用锁.
    • 但是实际上可能并没有其他线程来抢占这个锁. 这种情况 JVM 就会自动把锁粗化, 避免频繁申请释放锁.

    4. 总结

    可以看到, synchronized 的策略是比价复杂的, 在背后做了很多事情, 目的为了让程序猿哪怕啥都不懂, 也不至于写出特别慢的程序.

    在这里插入图片描述

  • 相关阅读:
    《自卑与超越》爱情篇
    计算机组成原理平时作业二
    神经网络(三)分类器与线性模型
    鸿蒙应用程序入口UIAbility详解
    FreeRTOS内存管理分析
    CSS 选择器-认识并应用选择器
    基于Java+SpringBoot+Mybatis+Vue+ElementUi的校园闲置物品交易
    SkiaSharp 之 WPF 自绘 投篮小游戏(案例版)
    关于Linux命令的使用
    数据结构哈希表(散列)Hash,手写实现(图文推导)
  • 原文地址:https://blog.csdn.net/zxj20041003/article/details/133963663