什么是无锁编程/lock-free/非阻塞式编程
在无锁状态下,协调线程对共享资源的获取,即不适用锁的情况下实现多线程之间变量的同步。
利弊
不对资源进行锁定那么就不需要调用操作系统底层的同步源语比如mutex,这样就减少了用户态和内核态的切换,在很大程度上提高多线程并发的性能,但缺点是无锁编程难度较高,控制更容易出错。
悲观锁和乐观锁
假设现在有很多个线程调用同一资源对象,我们的第一反应就是加互斥锁也就是悲观锁,什么是悲观锁呢?悲观锁就是悲观的认为如果不严格同步线程调用,那么就一定会产生异常,所以互斥锁会将资源锁定,只供一个线程调用,而阻塞其他线程。但悲观锁不是万能的,当我们大部分操作都是读操作的时候,或者同步代码块的耗时远远小于线程切换的耗时的情况下我们不想过度使用悲观锁也能协调线程对资源的调用。这种情况下就出现了CAS(Compare and Swap)。
CAS
Compare And Swap
了解CAS之前我们需要先了解CAS涉及到三个变量(V、E、N),V表示线程从主内存中读入的变量,E表示线程读取主内存中的最新值作为期望值,N表示要同步进主内存的新值。
在同步变量之前,每次都要比较V,E值是否相等,如果不相等就说明在当前线程修改这个变量同步回主内存之前有别的线程已经修改过这个变量,并且已经同步回主内存。所以当前线程不能把值同步回主内存,而是重新从主内存中读取该值,重复这整个操作(自旋)直到当前值(V)等于期望值(E),才将新值同步回主内存。
CAS同样存在着许多缺陷
1、线程长时间的自旋会带来很多cpu的消耗
2、会存在ABA问题
3、仅适用于单个变量的原子操作,不能用于多个变量的原子操作。
ABA问题
ABA问题简单来说就是在我同步变量前你将主内存中的值修改了之后又修改回我在主内存中读取到的V值,这样我的V,E值还是相等的。中间值更改过,但是不影响我后面的操作,这就是ABA问题。
解决办法就是给主内存中的变量加版本,做任何一个变量修改,修改完变量的版本号都加一,后面检查的时候连同版本号一起检查这样就可以有效解决ABA问题。