4

一个小伙伴私信我,他说遇到了一个关于CAS机制的问题,他以为面试官问的是CAS实现单点登录。

心想,这个问题我熟啊,然后就按照单点登录的思路去回答,结果面试官一直摇头。

他来和我说,到了面试结束都没明想白自己回答这么好,怎么就没有当场给我发offer呢?

实际上,面试官问的是并发编程中的CAS机制。

下面我们来看看普通人和高手对于CAS机制的回答吧

普通人:

CAS,是并发编程中用来实现原子性功能的一种操作,嗯,它类似于一种乐观锁的机制,可以保证并发情况下对共享变量的值的更改的原子性。

嗯, 像AtomicInteger这个类中,就用到了CAS机制。嗯…

高手:

CAS是Java中Unsafe类里面的方法,它的全称是CompareAndSwap,比较并交换的意思。它的主要功能是能够保证在多线程环境下,对于共享变量的修改的原子性。

我来举个例子,比如说有这样一个场景,有一个成员变量state,默认值是0,
carbon20220318001

定义了一个方法doSomething(),这个方法的逻辑是,判断state是否为0 ,如果为0,就修改成1。

这个逻辑看起来没有任何问题,但是在多线程环境下,会存在原子性的问题,因为这里是一个典型的,Read - Write的操作。

一般情况下,我们会在doSomething()这个方法上加同步锁来解决原子性问题。

但是,加同步锁,会带来性能上的损耗,所以,对于这类场景,我们就可以使用CAS机制来进行优化

这个是优化之后的代码
carbon20220318002

在doSomething()方法中,我们调用了unsafe类中的compareAndSwapInt()方法来达到同样的目的,这个方法有四个参数,

分别是:当前对象实例、成员变量state在内存地址中的偏移量、预期值0、期望更改之后的值1。

CAS机制会比较state内存地址偏移量对应的值和传入的预期值0是否相等,如果相等,就直接修改内存地址中state的值为1.

否则,返回false,表示修改失败,而这个过程是原子的,不会存在线程安全问题。

CompareAndSwap是一个native方法,实际上它最终还是会面临同样的问题,就是先从内存地址中读取state的值,然后去比较,最后再修改。

这个过程不管是在什么层面上实现,都会存在原子性问题。

所以呢,CompareAndSwap的底层实现中,在多核CPU环境下,会增加一个Lock指令对缓存或者总线加锁,从而保证比较并替换这两个指令的原子性。

CAS主要用在并发场景中,比较典型的使用场景有两个。

  1. 第一个是J.U.C里面Atomic的原子实现,比如AtomicInteger,AtomicLong。
  2. 第二个是实现多线程对共享资源竞争的互斥性质,比如在AQS、ConcurrentHashMap、ConcurrentLinkedQueue等都有用到。

以上就是我对这个问题的理解。

总结

最近大家也发现了我的文章内容在高手回答部分的变化。

有些小伙伴说,你面试怎么还能带图来,明显作弊啊。

其实主要是最近很多的面试题都偏底层,而底层的内容涵盖的知识面比较广,大家平时几乎没有接触过。

所以,如果我想要去把这些知识传递给大家,就得做很多的图形和内容结构的设计,否则大家看完之后还是一脸懵逼。

好的,本期的普通人VS高手面试系列就到这里结束了,喜欢的朋友记得点赞收藏。

我是Mic,一个工作了14年的Java程序员,咱们下期再见。
file

版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Mic带你学架构
如果本篇文章对您有帮助,还请帮忙点个关注和赞,您的坚持是我不断创作的动力。欢迎关注同名微信公众号获取更多技术干货!

跟着Mic学架构
810 声望1.1k 粉丝

《Spring Cloud Alibaba 微服务原理与实战》、《Java并发编程深度理解及实战》作者。 咕泡教育联合创始人,12年开发架构经验,对分布式微服务、高并发领域有非常丰富的实战经验。