一个小伙伴私信我,他说遇到了一个关于CAS机制的问题,他以为面试官问的是CAS实现单点登录。
心想,这个问题我熟啊,然后就按照单点登录的思路去回答,结果面试官一直摇头。
他来和我说,到了面试结束都没明想白自己回答这么好,怎么就没有当场给我发offer呢?
实际上,面试官问的是并发编程中的CAS机制。
下面我们来看看普通人和高手对于CAS机制的回答吧
普通人:
CAS,是并发编程中用来实现原子性功能的一种操作,嗯,它类似于一种乐观锁的机制,可以保证并发情况下对共享变量的值的更改的原子性。
嗯, 像AtomicInteger这个类中,就用到了CAS机制。嗯…
高手:
CAS是Java中Unsafe类里面的方法,它的全称是CompareAndSwap,比较并交换的意思。它的主要功能是能够保证在多线程环境下,对于共享变量的修改的原子性。
我来举个例子,比如说有这样一个场景,有一个成员变量state,默认值是0,
定义了一个方法doSomething()
,这个方法的逻辑是,判断state是否为0 ,如果为0,就修改成1。
这个逻辑看起来没有任何问题,但是在多线程环境下,会存在原子性的问题,因为这里是一个典型的,Read - Write的操作。
一般情况下,我们会在doSomething()这个方法上加同步锁来解决原子性问题。
但是,加同步锁,会带来性能上的损耗,所以,对于这类场景,我们就可以使用CAS机制来进行优化
这个是优化之后的代码
在doSomething()方法中,我们调用了unsafe类中的compareAndSwapInt()方法来达到同样的目的,这个方法有四个参数,
分别是:当前对象实例、成员变量state在内存地址中的偏移量、预期值0、期望更改之后的值1。
CAS机制会比较state内存地址偏移量对应的值和传入的预期值0是否相等,如果相等,就直接修改内存地址中state的值为1.
否则,返回false,表示修改失败,而这个过程是原子的,不会存在线程安全问题。
CompareAndSwap是一个native方法,实际上它最终还是会面临同样的问题,就是先从内存地址中读取state的值,然后去比较,最后再修改。
这个过程不管是在什么层面上实现,都会存在原子性问题。
所以呢,CompareAndSwap的底层实现中,在多核CPU环境下,会增加一个Lock指令对缓存或者总线加锁,从而保证比较并替换这两个指令的原子性。
CAS主要用在并发场景中,比较典型的使用场景有两个。
- 第一个是J.U.C里面Atomic的原子实现,比如AtomicInteger,AtomicLong。
- 第二个是实现多线程对共享资源竞争的互斥性质,比如在AQS、ConcurrentHashMap、ConcurrentLinkedQueue等都有用到。
以上就是我对这个问题的理解。
总结
最近大家也发现了我的文章内容在高手回答部分的变化。
有些小伙伴说,你面试怎么还能带图来,明显作弊啊。
其实主要是最近很多的面试题都偏底层,而底层的内容涵盖的知识面比较广,大家平时几乎没有接触过。
所以,如果我想要去把这些知识传递给大家,就得做很多的图形和内容结构的设计,否则大家看完之后还是一脸懵逼。
好的,本期的普通人VS高手面试系列就到这里结束了,喜欢的朋友记得点赞收藏。
我是Mic,一个工作了14年的Java程序员,咱们下期再见。