【JUC】12-CAS
1. CAS
compare and swap,比较并交换。
包含三个操作数:内存位置、预期原值及更新值。
执行CAS操作的时候,将内存位置的值与预期原值比较:
- 匹配,更新为新值。
- 不匹配,不进行操作,多个线程同时执行CAS操作只有一个会成功。
CAS是JDK提供的非阻塞原子性操作,通过硬件保证比较-更新的原子性。底层实现为CPU指令cmpxchg,效率更高。通过unsafe类实现。
2. 自旋
线程修改失败重试的过程叫自旋。
public static void main(String[] args) {
AtomicInteger integer = new AtomicInteger(5);
System.out.println(integer.compareAndSet(51, 200) + " " + integer.get());
}
自旋的实现代码
自己实现一个CAS。
public class SingletonLock {
AtomicReference<Thread> atomicThread = new AtomicReference<>();
public void Lock() {
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + "Lock");
// 当前不为空, 需要进行自旋
while (!atomicThread.compareAndSet(null, thread)) {
}
}
public void unLock() {
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + "unLock");
atomicThread.compareAndSet(thread, null);
}
public static void main(String[] args) {
SingletonLock singletonLock = new SingletonLock();
new Thread(()->{
singletonLock.Lock();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
singletonLock.unLock();
}, "t1").start();
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(()->{
singletonLock.Lock();
singletonLock.unLock();
}, "t2").start();
}
}
3. AtomicReference包装类
class Stu {
String name;
Integer age;
public Stu(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + ": " + age;
}
}
public class demo03 {
public static void main(String[] args) {
Stu zs = new Stu("zs", 18);
Stu ls = new Stu("ls", 29);
AtomicReference<Stu> atomicReference = new AtomicReference<>();
atomicReference.set(zs);
System.out.println(atomicReference.compareAndSet(zs, ls) + " " + atomicReference.get().toString());
}
}
4. CAS缺点
4.1 循环时间长,开销大
4.2 ABA问题
解决方案:版本号,戳记流水。
class Stus {
Integer id;
String name;
public Stus(Integer id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
}
public class demo04 {
public static void main(String[] args) {
Stus zs = new Stus(1, "zs");
Stus ls = new Stus(2, "ls");
AtomicStampedReference<Stus> atomicStampedReference = new AtomicStampedReference<>(zs, 1);
atomicStampedReference.compareAndSet(zs, ls, atomicStampedReference.getStamp(), 2);
System.out.println(atomicStampedReference.getReference().getName());
atomicStampedReference.compareAndSet(ls,zs, atomicStampedReference.getStamp(), 3);
System.out.println(atomicStampedReference.getReference().getName());
}
}