1. CAS
CAS 是无锁化编程,涉及 3 个值,内存地址、旧值、新值。
1.1 CAS 的问题
- ABA 问题
解决 ABA 问题方式是:加版本号。 - 开销问题
自旋 CAS 如果长时间不成功,会给 CPU 带来非常大的执行开销。 - 只能保证一个共享变量的原子操作
解决:想办法把多个变脸合并成一个变量,进行操作。
2. 原子操作
2.1 更新基本类型类
AtomicBoolean,AtomicInteger,AtomicLong
public class UseAtomicInt {
static AtomicInteger ai = new AtomicInteger(10);
public static void main(String[] args) {
ai.getAndIncrement();
ai.incrementAndGet();
ai.addAndGet(24);
}
}
2.2 更新数组类
AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
拷贝原数组,改变后原数组不会发生变化。
public class AtomicArray {
static int[] value = new int[]{1, 2};
static AtomicIntegerArray ai = new AtomicIntegerArray(value);
public static void main(String[] args) {
ai.getAndSet(0, 3);
System.out.println(ai.get(0));
System.out.println(value[0]);//原数组不会变化
}
}
2.3 更新引用类型
AtomicReference,AtomicMarkableReference,AtomicStampedReference
public class UseAtomicReference {
static AtomicReference<UserInfo> atomicUserRef;
public static void main(String[] args) {
UserInfo user = new UserInfo("Mark", 15);//要修改的实体的实例
atomicUserRef = new AtomicReference(user);
UserInfo updateUser = new UserInfo("Bill", 17);
atomicUserRef.compareAndSet(user, updateUser);
System.out.println(atomicUserRef.get());
System.out.println(user);
}
//定义一个实体类
static class UserInfo {
private volatile String name;
private int age;
public UserInfo(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "UserInfo{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
}
public class UseAtomicStampedReference {
static AtomicStampedReference<String> asr
= new AtomicStampedReference("mark", 0);
public static void main(String[] args) throws InterruptedException {
//拿到当前的版本号(旧)
final int oldStamp = asr.getStamp();
final String oldReference = asr.getReference();
System.out.println(oldReference + "============" + oldStamp);
Thread rightStampThread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":当前变量值:"
+ oldReference + "-当前版本戳:" + oldStamp + "-"
+ asr.compareAndSet(oldReference,
oldReference + "+Java", oldStamp,
oldStamp + 1));
}
});
Thread errorStampThread = new Thread(new Runnable() {
@Override
public void run() {
String reference = asr.getReference();
System.out.println(Thread.currentThread().getName()
+ ":当前变量值:"
+ reference + "-当前版本戳:" + asr.getStamp() + "-"
+ asr.compareAndSet(reference,
reference + "+C", oldStamp,
oldStamp + 1));
}
});
rightStampThread.start();
rightStampThread.join();
errorStampThread.start();
errorStampThread.join();
System.out.println(asr.getReference() + "============" + asr.getStamp());
}
}
2.4 原子更新字段类
AtomicReferenceFieldUpdater,AtomicIntegerFieldUpdater,AtomicLongFieldUpdater