前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java - CAS底层原理及与synchronized的对比

java - CAS底层原理及与synchronized的对比

作者头像
夹胡碰
发布2021-04-12 17:25:22
1.1K0
发布2021-04-12 17:25:22
举报
文章被收录于专栏:程序猿~程序猿~

底层原理疑问

CAS是比较并交换,AtomicInteger最终都是调用Unsafe.compareAndSwapInt方法进行实现,那Unsafe.compareAndSwapInt为什么是原子性的呢?它是怎么实现的?它的同步也是依赖于互斥吗?他与synchronized锁的底层实现有什么不同吗? 这两种同步方式的场景选择?

解答

1. Unsafe.compareAndSwapInt为什么是原子性的?

他的原子性是由硬件指令实现的,底层硬件通过将 CAS 里的多个操作在硬件层面语义实现上,通过一条处理器指令保证了原子性操作。这些指令如下所示: (1)测试并设置(Tetst-and-Set) (2)获取并增加(Fetch-and-Increment) (3)交换(Swap) (4)比较并交换(Compare-and-Swap) (5)加载链接/条件存储(Load-Linked/Store-Conditional)

前面三条大部分处理器已经实现,后面的两条是现代处理器当中新增加的。而且根据不同的体系结构,指令存在着明显差异。 在IA64,x86 指令集中有cmpxchg指令完成 CAS 功能,在 sparc-TSO 也有 casa 指令实现,而在 ARM 和 PowerPC 架构下,则需要使用一对 ldrex/strex 指令来完成 LL/SC 的功能。在精简指令集的体系架构中,则通常是靠一对儿指令,如:load and reserve 和 store conditional 实现的,在大多数处理器上 CAS 都是个非常轻量级的操作,这也是其优势所在。

2. 怎么实现的

它采用了缓存锁定 现在都是多核 CPU 处理器,每个 CPU 处理器内维护了一块字节的内存,每个内核内部维护着一块字节的缓存,当多线程并发读写时,就会出现缓存数据不一致的情况。 此时,处理器提供:

  • 总线锁定 当一个处理器要操作共享变量时,在 BUS 总线上发出一个 Lock 信号,其他处理就无法操作这个共享变量了。 缺点很明显,总线锁定在阻塞其它处理器获取该共享变量的操作请求时,也可能会导致大量阻塞,从而增加系统的性能开销。
  • 缓存锁定 后来的处理器都提供了缓存锁定机制,也就说当某个处理器对缓存中的共享变量进行了操作,其他处理器会有个嗅探机制,将其他处理器的该共享变量的缓存失效,待其他线程读取时会重新从主内存中读取最新的数据,基于 MESI 缓存一致性协议来实现的。 现代的处理器基本都支持和使用的缓存锁定机制。
3. 它的同步也是依赖于互斥吗?他与synchronized锁的底层实现有什么不同吗?

它与synchronized最大的不同就是,CAS采用的缓存锁定,在没有竞争的时候没有额外的操作,当有竞争了才会有通知缓存失效机制。而synchronized是采用悲观互斥锁,即使没有线程竞争也会加上monitorentermonitorexit指令(不考虑jdk1.6之后的锁优化),会有线程的阻塞行为,影响性能。

4. 场景选择

CAS - 竞争小的情况,竞争过多造成自旋过多,造成cpu空跑 synchronized - 竞争大的情况,竞争过小加悲观锁比较重

参考

  1. 一文彻底搞懂CAS实现原理
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 底层原理疑问
  • 解答
    • 1. Unsafe.compareAndSwapInt为什么是原子性的?
      • 2. 怎么实现的
        • 3. 它的同步也是依赖于互斥吗?他与synchronized锁的底层实现有什么不同吗?
          • 4. 场景选择
          • 参考
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档