观看视频。根据以下视屏,写的笔记
【Java并发】面试官问我CAS、乐观锁、悲观锁,我反手就是骑脸输出_哔哩哔哩_bilibili
悲观锁
假设现在有多个线程想要操作同一个资源对象
很多人的第一反应就是使用互斥锁,但是互斥锁的同步方式是悲观的。
什么是悲观呢
简单来说操作系统将会悲观的认为,如果不严格同步线程调用,那么一定会产生异常。所以互斥锁将会将资源锁定,只供一个线程调用,而阻塞其他线程,因此这种同步机制也叫悲观锁。但是悲观锁不是万能的。
比如在一些情况下,大部分调用可能都是读操作,那么就没有必要在每次调用的时候都锁定资源;或者在一些情况下,同步代码块执行的耗时远远小于线程切换的耗时,那么使用这种锁就有些本末倒置了。所以在这种情况下,我们不想操作系统这么悲观,我们不想过度使用互斥锁。
乐观锁
在我们的设想中能不能不对共享资源锁定也能对线程调用进行协调?
因此诞生一种非常经典和巧妙的算法叫CAS(compare and swap)
当资源对象的状态值为0的一瞬间,AB两条线程都读到了,此时这两条线程认为资源对象当前的状态值是0,于是他们就会各自产生两个值old value 代表之前读到的资源对象的状态值,new value代表想要将资源对象的状态值更新后的值。这里对两条线程来说old value都是0,new value都是1。
此时AB线程争抢着去修改资源对象的状态值,然后占用他。假设a线程率先获得时间片,他将old value 与资源对象的状态值进行compare(比较)发现一致。于是将牌子上面的值swap(交换)为new value。而b线程因为落后了一步,资源状态的值被a线程修改为1,b线程在compare的时候发现值与自己预期的old value不一致,所以放弃swap操作。但实际应用中,我们不会让b线程直接放弃。通常会使其自旋(不断重复CAS操作)通常会配置自旋次数防止死循环。
CAS必须是原子性的,各种不同架构的CPU都提供了指令级别的CAS原子操作。也就是不需要通过操作系统的同步原语CPU已经原生的支持 CAS,上层进行调用即可,这样我们就能不再依赖锁来实现线程同步。但这并不意味着无锁能够完全代替有锁。
这些通过CAS来实现同步的工具,由于不会锁定资源,而且当线程需要修改共享资源的对象式时,总是会乐观的认为对象状态值没有被其他线程修改过,而是每次自己会主动尝试去compare状态值。相较于上文提到的悲观锁,这种同步机制被称为乐观锁。