背景
现在有多个线程想要操作同一资源对象,很多人一上来就会选择互斥锁,但是有一个问题就是:互斥锁的同步方式是悲观的。所谓悲观就是,操作系统会悲观的认为:如果不严格同步线程调用,那么一定会产生异常,所以互斥锁将会将资源进行锁定,直供一个线程调用而阻塞其他的线程,这样的同步机制叫做悲观锁。
但是悲观锁不是万能的,如果在大量调用都是读操作的情况下,那么就没有必要在每次调用的时候都锁定资源。或者在一些情况下,同步代码的耗时远远小于线程切换的耗时,现在选择悲观锁的话就显得本末倒置了。
这是就提出了一个问题,能否不锁定资源,也能同步线程。
CAS
CAS(Compare And Swap)比较和交换。例如,资源对象有着0、1两个状态,现在有两个线程A、B去读取资源对象的状态。当资源对象的状态值为0的一瞬间,ab线程都读到了,此时这两条线程认为资源对象的状态值为0,于是它们各自将会生成两个值,Old Value代表之前读到的资源对象的状态值,New Value代表想要更新资源对象的状态值。
此时A、B线程都会去争抢着去修改资源对象的状态值,然后占用它。假设A线程率先获得了时间片,它将old value与资源对象的状态值进行compare发现一致,于是将资源对象的值swap为new value = 1。但是B线程发现此时old value和资源对象的值不一致,所以就放弃了swap操作。
但是在实际应用中,通常会使B线程进行自旋(自旋,就是使其不断地重试CAS操作),通过配置自旋的次数来防止死循环。
需要注意的是compare和swap这两个动作必须“被绑定”,在同时只能有一条线程进行操作,即CAS是原子性的。
CAS原子性:
- x86架构下,通过cmpxchg指令支持CAS原子性
- ARM架构下,通过LL/SC来实现CAS的原子性