大纲:
- cas
- atomic
一、cas
cas:compareAndSwap,一种乐观锁。
cas思想:cas需要三个值,v是内存值,e是期望值,n是要修改的值。当内存中的值v等于预期值e(说明内存中的值没有被其他线程修改)、才可以修改v为n。
cas伪代码
boolean cas(int v,int e,int n){
if(v==e){
v=n;
return true;
}else {
return false;
}
}
cas是unsafe类中的native方法,是原子操作,保证线程安全。
二、atomic
在java.util.concurrent.atomic包中,提供了许多拥有原子操作的类,供并发编程使用。这个包中的类大都使用了cas操作来保证操作的原子性。
以AtomicInteger为例,看下如何使用cas实现原子操作,这里为java1.8以下的源码:
public class AtomicInteger extends Number implements java.io.Serializable { private volatile int value; //volatile保证可见性,一个线程更新后,其他线程立即可见 public final int get() { return value; } public AtomicInteger(int initialValue) { value = initialValue; } public final int getAndIncrement() { for (;;) { int current = get();//预期值e int next = current + 1;//要修改的值n if (compareAndSet(current, next)) return current; } //这个相当于线程安全的a++操作,其思想就是不断进行cas操作,直至成功 } public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); //给bootStrap类加载器用的unsafe中全部是native方法。 // valueOffset为变量在内存中偏移地址,用来找内存中的值v } ...... }
ABA问题:一个线程在cas操作时,期望值是A,另一个线程修改了期望值为B,就会导致cas操作失败。但是如果这时候又有一个线程再次修改期望值为A,cas操作将成功。
如何解决:atomic包下AtomicStampedReference
public class AtomicStampedReference<V> { private static class Pair<T> { final T reference; final int stamp; private Pair(T reference, int stamp) { this.reference = reference; this.stamp = stamp; } static <T> Pair<T> of(T reference, int stamp) { return new Pair<T>(reference, stamp); } } private volatile Pair<V> pair; public AtomicStampedReference(V initialRef, int initialStamp) { pair = Pair.of(initialRef, initialStamp); //AtomicStampedReference内部有一个静态内部类pair,pair不仅封装了数据还封装了一个stamp用于区分每次修改 } public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) { Pair<V> current = pair; return expectedReference == current.reference && expectedStamp == current.stamp && ((newReference == current.reference && newStamp == current.stamp) || casPair(current, Pair.of(newReference, newStamp))); //cas比较pair对象(不仅比较内存值如期望值,同时比较期望stamp与内存stamp) } private boolean casPair(Pair<V> cmp, Pair<V> val) { return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); } ... }