今天听同事培总讲了下CAS,进行简单总结。
CAS(Compare and Swap)比较交换算法,非锁机制保证原子性操作。适用于读多写少的时候
CAS操作一般分为:
1.读共享内存值到工作内存
2.比较共享内存值与工作内存是否相等
3.如果相等,将运算结果值刷到共享内存
其中三步操作不可分割,称为原子性
一般CAS的操作数为三个 : V A B
其中 V称为旧值,A称为期望值, B称为结果值
举个栗子
有一个自增操作 i++,多个线程即将开始自增操作。每个线程都会将共享内存中的1刷到私有的工作内存中。
此时A线程开始自增操作,分为三步,A需要更改前,将A工作内存中的值作为期望值A,试图与共享内存中的旧值V比较,如果一样,开始swap操作,将自增后的操作数值B写入到共享内存中。其中三步操作时不可分割的,称为原子性。此时图为
此时B线程试图去自增,它先去共享内存中取旧值V = 2 ,与B线程中的期望值A比较,此时发现不一样,B线程就开始进行自旋操作,去获取共享内存中的值作为新的期望值。下来一般分为两种结果
1.B获取到新的期望值A=2,与共享内存中的旧值V比较,结果相等,进行了自增操作,操作结束。
2.B获取到新的期望值A=2,与共享内存中的值比较前,C线程已经先于B执行自增操作,将共享内存中的旧值V改为了3,此时B发现旧值V=3与期望值A=2不等,它就继续自旋,尝试获取共享内存当前值作为期望值,如果B运气比较差,每次自旋完成替换期望值,但共享内存中的旧值V总是被人先一步更改掉,B线程就会不断自旋获取共享内存中的值刷到自己的工作内存作为期望值A。直到A=V ,B线程将结果值B刷到共享内存中。
图简单画下
此时,就实现了非锁机制实现原子性了。而volatile之所以不能原子性,是因为,他的操作不像CAS算法三步操作一样不可分割。
在JAVA中Atomic接口就大量使用了CAS算法,例如AtomicInteger中的get与set方法中就使用了这种操作。
CAS优点:非锁机制实现原子性,内存消耗少
缺点:写操作较多时,容易发生不断自旋,不断比较不同,继续自旋获取新值,造成资源消耗