参考文章:https://cloud.tencent.com/developer/article/1496220
CAS(Compare-And-Swap)(比较并交换)(无锁优化 自旋 乐观锁)
例如,一个线程在使用AtomicInteger原子变量进行修改值的操作中,底层就是CAS算法,CAS有个三参数:内存值V,预期值A,新值B,当且仅当预期值A和内存值V相同时,才会将内存值修改为新值B并返回true,否则什么都不做,并返回false
Unsafe类是CAS的核心类,Unsafe里有可以直接操作特定内存数据的方法,内部方法操作可以像C指针一样操作内存,所以CAS操作的执行依赖于Unsafe类的方法
缺点:
1.循环时间长开销大
如果CAS失败,会一直循环尝试,如果一直不成功,可能会给CPU带来很大开销
2.只能保证一个共享变量的原子操作
3.会出现ABA问题
解决ABA问题
加version,使用AtomicStampedreference
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
public class TestAtomicStampedReference {
static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);
public static void main(String[] args) {
new Thread(() -> { int stamp = atomicStampedReference.getStamp(); System.out.println(Thread.currentThread().getName() + "\t第一次时间戳" + stamp);
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
atomicStampedReference.compareAndSet(100, 101, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1); System.out.println(Thread.currentThread().getName() + "\t第一次修改版本号 : "+atomicStampedReference.getStamp()); atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1); System.out.println(Thread.currentThread().getName() + "\t第二次修改版本号 : "+atomicStampedReference.getStamp());
}, "T1").start();
new Thread(() -> { int stamp = atomicStampedReference.getStamp(); System.out.println(Thread.currentThread().getName() + "\t线程获得的版本号 :"+stamp);
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
Boolean flag = atomicStampedReference.compareAndSet(100, 2019, stamp, stamp + 1);
System.out.println(Thread.currentThread().getName() + "\t修改是否成功"+flag + "\t此时的版本号" + atomicStampedReference.getStamp());
}, "T2").start(); }
}
|