ABA问题的产生,与解决方法:原子引用更新+版本号修改
package com.myspringboot.test;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;
/*
* @Description: 加时间戳的原子引用解决ABA问题,AtomicStampedReference
* @Author: WDC
* @Date: 2020/3/19 11:35
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
class Person{
private Integer id;
private String name;
}
/*
* @Description: CAS 比较并交换,比较 期望值 和 实际值 而不关注中间发生了什么,这就是ABA问题
* ABA问题解决,通过引用原子更新 + 版本号修改解决,
* 原理:每次CAS后 修改版本号,最后即使CAS时 期望值与实际值相同,但版本号是不同的,修改失败,重写读取并修改
* @Author: WDC
* @Date: 2020/3/19 12:25
**/
public class AtomicReferenceDemo {
static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);
public static void main(String[] args) {
System.out.println("==================以下是ABA问题的产生");
new Thread(()->{
atomicReference.compareAndSet(100,101);
atomicReference.compareAndSet(101,100);
},"AA").start();
new Thread(()->{
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(atomicReference.compareAndSet(100,2019)+"\t"+atomicReference.get());;
},"BB").start();
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("==================以下是ABA问题的解决");
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());
},"CC").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 result = atomicStampedReference.weakCompareAndSet(100,2019,stamp,stamp+1);
System.out.println(Thread.currentThread().getName() + "\t修改成功否" + result + "\t当期最新实际本版号"+atomicStampedReference.getReference());
},"DD").start();
}
}