V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yodhcn
V2EX  ›  Java

[ Java 八股] 为什么说 synchronized 锁是重量级的?基于 AQS 的锁在 [阻塞线程] 时,就不涉及用户态&内核态的切换了吗?

  •  
  •   yodhcn ·
    yodhcn · 2023-10-27 11:46:31 +08:00 · 2374 次点击
    这是一个创建于 386 天前的主题,其中的信息可能已经有所发展或是发生改变。
    第 1 条附言  ·  2023-10-27 19:08:08 +08:00
    根据这篇文章的介绍
    https://zhuanlan.zhihu.com/p/137624149?utm_id=0

    基于 AQS 都锁的线程的阻塞、唤醒是通过工具类 java.util.concurrent.locks.LockSupport 实现的
    LockSupport.park(Object blocker) // 阻塞线程
    LockSupport.unpark(Thread thread) // 唤醒线程

    而 park 和 unpark 方法都是通过 sun.misc.UNSAFE 类中的 park 和 unpark 方法来实现的(这 2 个方法都是本地方法)

    就是不知道这两个 native 方法是怎样实现的。。。
    12 条回复    2023-10-30 17:58:07 +08:00
    Leviathann
        1
    Leviathann  
       2023-10-27 11:52:18 +08:00
    虚拟线程不支持 synchronized ,会导致物理线程阻塞,你就说他重不重吧
    yodhcn
        2
    yodhcn  
    OP
       2023-10-27 12:07:41 +08:00
    @Leviathann #1
    感谢老哥的回答!
    但我还有疑问,请您解惑

    1. 我不太了解虚拟线程,从除了虚拟线程以外的角度回答,还有别的缺点吗?
    2. AQS 的锁在 [阻塞线程] 时,涉及用户态&内核态的切换吗?
    3. synchronized Moniter 锁与 AQS 在阻塞线程的方式相同吗?区别大吗?
    xxxrubyxxx
        3
    xxxrubyxxx  
       2023-10-27 12:39:05 +08:00
    1.是否涉及切换和是否使用 syscall 相关,这两个都会使用 park 挂起线程
    2. sync 和 aqs 的实现差别不太大,都是先 cas 尝试,没拿到锁再去挂起线程,去 queue 里排队
    oldking24
        4
    oldking24  
       2023-10-27 13:33:55 +08:00 via Android
    synchronized 一旦升级就不会降级吧,但是 aqs 正常都会去 cas 一下
    cxshun
        5
    cxshun  
       2023-10-27 13:37:17 +08:00
    1. synchronized 涉及到锁升级流程,并不是一来就上重量级锁,如果只是偏向锁,成本不高,根本就不涉及到内核态的切换,就算是轻量级的,也直接用 CAS 来解决;再来才是重量级的。
    2. AQS 的锁本质上是用 CAS 来实现的,这个其实就和内核态没什么太大关系了。
    xiaxiaocao
        6
    xiaxiaocao  
       2023-10-27 13:45:03 +08:00
    最早的时候 synchronized 直接系统调用的,哪怕加锁成功也是有上下文切换,因此说是重量级。
    1.6 之后也会先 CAS ,跟 Lock 差别不大了。
    shalk
        7
    shalk  
       2023-10-27 13:58:35 +08:00
    所以你原本的问题应该是,sync 和 reentrainlock 的区别? 1.8 下面性能区别不大
    4kingRAS
        8
    4kingRAS  
       2023-10-27 14:40:38 +08:00
    之所以说 synchronized 有进入内核态是因为用到了 mutex 系统调用,而 AQS 底层是依赖 cmpxchg 指令,不涉及内核态
    broken123
        9
    broken123  
       2023-10-27 14:46:59 +08:00
    我只晓得 Java 的所有的锁 目前都是 aqs 接口实现的 然后 aqs 的底层原理是机遇 cpu 的 cas 原理实现的 和操作系统内核无关。只和 cpu 有关系
    Jrue0011
        10
    Jrue0011  
       2023-10-27 15:30:03 +08:00   ❤️ 1
    网上搜了下,感觉重量级只是说当锁膨胀到最后一个阶段,如果抢不到锁会从用户态切换到内核态挂起等待,相对前面阶段的偏向锁和轻量级锁重的说法吧,而不是跟 Lock 的对比?另外就是楼上说的 1.6 之前因为没有偏向锁、轻量级锁的优化,上来就是第三个阶段。这样看的话 1.6 之前 synchronized 和 Lock 差不多,现在如果是竞争少的情况下反而 synchronized 更优。

    以 Linux 举例,synchronized 在第三阶段的 ObjectMonitor 以及 AQS 的 LockSupport.park/Unsafe.park 好像都是 CAS + futex_wait (手动狗头下,我也不知道我说的对不对,都是搜到的资料)。
    Aresxue
        11
    Aresxue  
       2023-10-30 10:34:40 +08:00   ❤️ 2
    都会进入内核态,只是 synchronized 的重量级锁底层是插入了 monitorenter 和 monitorexit 两个指令,以最流行的 JVM HotSpot 为例其底层使用了 mutex ( linux 下)这个非常重的锁,而对于 AQS 使用的 LockSupport 的 park 和 unpark ,其底层会使用操作系统提供的原语,如 pthread_cond_wait (对于 POSIX 线程库)或 Windows 上的 WaitForSingleObject 等来实现线程的挂起,再使用 pthread_cond_signal (对于 POSIX 线程库)或 Windows 上的 SetEvent 等来实现线程的唤醒,这些操作系统原语通常是高效的,允许线程在等待期间几乎不占用 CPU 资源,从而有效地实现了非阻塞的线程等待和唤醒。

    不过 1.8 以后性能大差不差了(很多东西也互相借鉴其实逻辑上已经高度相似),只是 AQS 系列的锁更灵活 api 更好用,如果只有上锁解锁随便用哪个。
    huang119412
        12
    huang119412  
       2023-10-30 17:58:07 +08:00   ❤️ 1
    你确定你没有搞错? synchronized 重量级是相对于 CAS 的。AQS 比 synchronized 重量级,synchronized 性能比基于 AQS 的同步类,性能高一个数量级,只是 AQS 更灵活一些。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2634 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 04:26 · PVG 12:26 · LAX 20:26 · JFK 23:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.