CAS(compare and swep)比较然后交换
通常需要三个参数,一个是预期值,一个是当前值,一个是替换值
逻辑是 当 预期值 与 当前值 相等时,替换值进行替换,同时返回true。
ABA问题
因为CAS需要在操作值的时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么CAS进行检查时会发现它的值没有发生变化,但是实际上已经发生了变化。
譬如
对于这个问题Atomic包里面自带的AtomicStampedReference类能够解决这个问题,解决思路就是对于一个值设置一个版本号,更改一次改变一次,进行CAS时不光需要核对Value还要核对版本号。
代码:
1 package thread; 2 3 import java.util.concurrent.TimeUnit; 4 import java.util.concurrent.atomic.AtomicStampedReference; 5 6 /** 7 * 解决ABA问题,atomic包里面自带的AtomicStampedReference类 8 */ 9 public class AtomicStampedReferenceDemo { 10 public static AtomicStampedReference<Integer> atomicStampedReference = 11 new AtomicStampedReference<Integer>(100,0); 12 13 public static void main(String[] args) { 14 Thread intT1 = new Thread(new Runnable() { 15 16 @Override 17 public void run() { 18 try { 19 TimeUnit.SECONDS.sleep(1); 20 } catch (InterruptedException e) { 21 e.printStackTrace(); 22 } 23 atomicStampedReference.compareAndSet(100,101, 24 atomicStampedReference.getStamp(), 25 atomicStampedReference.getStamp() + 1); 26 atomicStampedReference.compareAndSet(101,100, 27 atomicStampedReference.getStamp(), 28 atomicStampedReference.getStamp() + 1); 29 } 30 }); 31 Thread intT2 = new Thread(new Runnable() { 32 33 @Override 34 public void run() { 35 int stamp = atomicStampedReference.getStamp(); 36 System.out.println(stamp);//0 37 try { 38 //相当于Thread.sleep,能够自定义单位 39 TimeUnit.SECONDS.sleep(2); 40 } catch (InterruptedException e) { 41 e.printStackTrace(); 42 } 43 Boolean b = atomicStampedReference.compareAndSet(100, 101, 44 stamp, 45 stamp + 1); 46 System.out.println(b);//false 47 System.out.println(atomicStampedReference.getReference());//100 48 } 49 }); 50 51 52 intT1.start(); 53 intT2.start(); 54 } 55 56 }