引言:更多相关请看 JAVA并发编程系列
ABA问题
CAsS算法实现一个重要前提需要取出内存中某时刻的数据并在当下时刻比较并替换,那么在这个时间差类会导致数据的变化。比如说一个线程one从内存位置v中取出A,这时候另一个线程two也从内存中取出A,并且线程two进行了一些操作将值变成了B,然后线程two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后线程one操作成功。尽管线程one的CAS操作成功,但是不代表这个过程就是没有问题的。
原子引用AtomicReference
包java.util.concurrent.atomic下

@Data
@AllArgsConstructor
@NoArgsConstructor
class User {
private String name;
private int age;
}
class AtomicReferenceDemo {
public static void main(String[] args) {
User root = new User("root", 22);
User admin = new User("admin", 22);
AtomicReference<User> userAtomicReference = new AtomicReference<>();
userAtomicReference.set(root);
// true User(name=admin, age=22)
System.out.println(userAtomicReference.compareAndSet(root, admin) + "\t" + userAtomicReference.get().toString());
// false User(name=admin, age=22)
System.out.println(userAtomicReference.compareAndSet(root, admin) + "\t" + userAtomicReference.get().toString());
}
}
时间戳原子引用AtomicStampedReference
解决ABA问题:
AtomicStampedReference类的compareAndSet方法

class ABADemo {
private static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
private static AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<>(100, 1);
public static void main(String[] args) {
System.out.println("=================ABA问题产生=================");
new Thread(() -> {
// 完成ABA
atomicReference.compareAndSet(100, 101);
atomicReference.compareAndSet(101, 100);
}, "t1").start();
new Thread(() -> {
// 先暂停1秒 保证完成ABA
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(atomicReference.compareAndSet(100, 2019) + "\t" + atomicReference.get());
}, "t2").start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("=================ABA问题解决=================");
int stamp = stampedReference.getStamp();// 初始版本号
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"初始值:"+stampedReference.getReference() + " 版本号:"+stamp);
stampedReference.compareAndSet(100, 101, stamp, stamp + 1);
stampedReference.compareAndSet(101, 100, stampedReference.getStamp(), stampedReference.getStamp() + 1);
System.out.println(Thread.currentThread().getName()+"最终值:"+stampedReference.getReference() + " 版本号:"+stampedReference.getStamp());
}, "t3").start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"初始值:"+stampedReference.getReference() + " 版本号:"+stamp);
// 先暂停1秒 保证完成ABA
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"修改状态:"+stampedReference.compareAndSet(100, 2019, stamp,stamp+1));
System.out.println(Thread.currentThread().getName()+"ABA最终值:"+stampedReference.getReference() + " ABA最终版本号:"+stampedReference.getStamp());
}, "t4").start();
}
}
效果:
