Tiefes Verständnis von CAS und atomaren Referenzen
Ein tiefgreifendes Verständnis von CAS
Was ist CAS?
ublic class CASDemo {
//CAS compareAndSet:比较并交换
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2020);
// 期望、更新
// public final boolean compareAndSet(int expect, int update)
// 如果我期望的值达到了,那么就更新,否则,就不更新, CAS 是CPU的并发原语!
// ============== 捣乱的线程 ==================
System.out.println(atomicInteger.compareAndSet(2020,2021));
System.out.println(atomicInteger.get());
//atomicInteger.getAndIncrement();
System.out.println(atomicInteger.compareAndSet(2021,2020));
System.out.println(atomicInteger.get());
// ============== 期望的线程 ==================
System.out.println(atomicInteger.compareAndSet(2020,6666));
System.out.println(atomicInteger.get());
}
}
unsichere Klasse
Wortoperationsspeicher hinter der obigen Abbildung
CAS: Vergleichen Sie den Wert im aktuellen Arbeitsspeicher mit dem Wert im Hauptspeicher. Wenn dieser Wert erwartet wird, führen Sie die Operation aus! Wenn dies nicht der Fall ist, führen Sie eine Schleife durch!
Nachteile:
1. Der Zyklus ist zeitaufwändig
2. Nur einmal kann die Atomizität einer gemeinsam genutzten Variablen garantiert werden
3. ABA-Problem
CAS: ABA-Problem (Zibetkatze für Prinz)
public class CASDemo {
// CAS compareAndSet 比较并交换
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2020);
// 期望、更新
// public final boolean compareAndSet(int expect, int update)
// 如果期望得值成功了,那么就更新,否则就不更新 CAS是CPU的并发原语。
// ============== 捣乱的线程 ==================
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
System.out.println(atomicInteger.compareAndSet(2021, 2020));
System.out.println(atomicInteger.get());
// ============== 期望的线程 ==================
System.out.println(atomicInteger.compareAndSet(2020, 6666));
System.out.println(atomicInteger.get());
}
}
2. Atomzitat
Lösen Sie das ABA-Problem und führen Sie atomare Referenzen ein! Entsprechender Gedanke: optimistisches Schloss!
Atombetrieb mit Versionsnummer!
public class CASDemo {
// AtomicStampedReference 注意,如果泛型是一个包装类,注意对象的引用问题,范围内用同一个,超出自动new新的
// 正常在业务操作,这里面比较的都是一个个对象
static AtomicStampedReference<Integer> atomicStampedReference = new
AtomicStampedReference<>(1, 1);
// CAS compareAndSet : 比较并交换!
public static void main(String[] args) {
new Thread(() -> {
int stamp = atomicStampedReference.getStamp(); // 获得版本号
System.out.println("a1=>" + stamp);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicStampedReference.compareAndSet(1, 2,
atomicStampedReference.getStamp(),
atomicStampedReference.getStamp() + 1);
System.out.println("a2=>" + atomicStampedReference.getStamp());
System.out.println(atomicStampedReference.compareAndSet(2, 1,
atomicStampedReference.getStamp(),
atomicStampedReference.getStamp() + 1));
System.out.println("a3=>" + atomicStampedReference.getStamp());
}, "a").start();
// 乐观锁的原理相同!
new Thread(() -> {
int stamp = atomicStampedReference.getStamp(); // 获得版本号
System.out.println("b1=>" + stamp);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(atomicStampedReference.compareAndSet(1, 6,
stamp, stamp + 1));
System.out.println("b2=>" + atomicStampedReference.getStamp());
}, "b").start();
}
}
Hinweis:
Integer verwendet den Objekt-Caching-Mechanismus. Der Standardbereich ist -128 ~ 127. Es wird empfohlen, die statische Factory-Methode valueOf zu verwenden, um Objektinstanzen anstelle von new abzurufen, da valueOf das Caching verwendet und new definitiv neue Objekte erstellt und neuen Speicher zuweist Platz;