乐观锁有ABA问题,如果遇到特殊需求,就有问题。
比如更新会造成系统数据更新,有安全漏洞,尤其金融系统。
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class ABADemo {
static AtomicInteger atomicInteger = new AtomicInteger(100);
public static void main(String[] args) {
new Thread(()->{
atomicInteger.compareAndSet(100,101);
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicInteger.compareAndSet(101,100);
},"t1").start();
new Thread(()->{
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicInteger.compareAndSet(100,2022);
System.out.println("result value:"+atomicInteger.get());
},"t2").start();
}
}
result value:2022
解决方案
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;
public class ABAVersionDemo {
static AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<>(100,1);
public static void main(String[] args) {
new Thread(()->{
int stamp = stampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+"\t"+"首次版本号"+stamp);
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
stampedReference.compareAndSet(100,101,stampedReference.getStamp(),stampedReference.getStamp()+1);
System.out.println(Thread.currentThread().getName()+"\t"+"2次版本号:"+stampedReference.getStamp());
stampedReference.compareAndSet(101,100,stampedReference.getStamp(),stampedReference.getStamp()+1);
System.out.println(Thread.currentThread().getName()+"\t"+"3次版本号:"+stampedReference.getStamp());
},"t3").start();
new Thread(()->{
int stamp = stampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+"首次版本号:"+stamp);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean flag = stampedReference.compareAndSet(101,2002,stampedReference.getStamp(),stampedReference.getStamp()+1);
System.out.println("flag:"+flag);
System.out.println(stampedReference.getReference()+"\t"+stampedReference.getStamp());
},"t4").start();
}
}
t3 首次版本号1
t4首次版本号:1
t3 2次版本号:2
t3 3次版本号:3
flag:false
100 3
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.atomic.AtomicStampedReference;
public class AtomicMarkedReferenceTest {
static AtomicMarkableReference atomicMarkableReference = new AtomicMarkableReference(100,false);
public static void main(String[] args) {
new Thread(()->{
boolean marked = atomicMarkableReference.isMarked();
System.out.println(Thread.currentThread().getName()+"\t"+"首次版本号"+marked);
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicMarkableReference.compareAndSet(100,1000,marked,!marked);
},"t3").start();
new Thread(()->{
boolean marked = atomicMarkableReference.isMarked();
System.out.println(Thread.currentThread().getName()+"\t"+"首次版本号"+marked);
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean flag = atomicMarkableReference.compareAndSet(100,2002,marked,!marked);
System.out.println("flag:"+flag);
System.out.println(atomicMarkableReference.getReference()+"\t"+atomicMarkableReference.isMarked());
},"t4").start();
}
}
AtomicMarkableReference : 只能用一次,类似一次性筷子
AtomicStampedReference:version 多次叠加