【Java并发】面试官问我CAS、乐观锁、悲观锁,我反手就是骑脸输出

面试常问:
- 了解CAS吗?谈谈理解
- 用过AQS吗?举个例子
- 读过JUC源码吗?具体实现

P.S. 互斥锁:比如synchronized关键字、ReentrantLock
参考:https://blog.csdn.net/jiyiqinlovexx/article/details/51010176
悲观锁(Pessimistic Concurrency Control)
悲观:OS认为,若不严格同步(sync)线程调用,则一定会产生异常。
故:互斥锁将一个资源锁定,仅供一个线程调用,阻塞其他线程。



compare and swap
oldValue:代表之前读到的资源对象的状态值
newValue:代表享要将资源对象的状态值更新后的值

“此时AB线程争抢着去修改资源对象的状态值,然后占用它”

设a抢到了时间片,
a 对比 对象状态值=0, oldValue=0
二者compare,结果相等,符合预期,则swap对象状态值为1
b 对比 对象状态值=1, oldValue=0。
二者compare,结果不等,抢占失败,放弃swap操作。
实际应用,通常会让b进行自旋(不断第重试cas操作,且配置次数避免死循环)


没有同步操作,还是线程不安全
(若同时抢到,则同时swap为1,同步失败)

故,要是CAS线程安全,则:
campare和swap必须“被绑定”
- campare & swap这个操作,必须满足同一时刻只能允许1个线程在进行
即 CAS必须是原子性的

各种架构的CPU提供了指令级别的CAS原子操作:
- x86: cmpxchg
- arm: LL/SC
即无需通过OS的同步原语(mutex),CPU硬件原生支持CAS,上层进行调用即可
但这不代表“无锁”能代替“有锁”。
乐观锁(Optimistic Concurrency Control):
- 不会锁定资源
- 当线程想要修改共享资源的对象时,总是会乐观地认为,对象状态值没有被其他线程修改过,而是每次都会自己主动尝试去compare状态值

乐观“锁”取名不恰当:因为其并没有用到锁,实为无锁的同步机制
示例需求:使用3个线程,将一个值,从0累加到1000
错误1 不使用任何同步机制

改进1 使用互斥锁同步线程

改进2 使用无锁编程同步线程
Atomic类是无锁编程的轮子
AtomicInteger 底层通过CAS来实现同步的计数器

Unsafe类型的示例
一个long类型的offset

直接调用unsafe对象的 incrementAndGet方法


自旋循环次数,可配置,默认为10

native boolean compareAndSwapInt
是一个本地方法
