1 CAS
CAS,即compare and swap。
CAS操作是原子操作,在多线程中执行CAS操作可以实现同步。
CAS操作中包含三个操作数,分别是内存地址、预期原值和新值。首先比较这个内存地址存放的数值和预期原值,如果二者相等,将这个内存地址存放的数值设为新值,CAS操作成功;如果二者不相等,CAS操作失败。CAS操作的原子性可以确保这个内存地址存放的数值是根据预期原值计算得到的。
CAS操作中的问题:ABA问题,循环时间长开销大,只能保证一个共享变量的原子操作。
2 CAS操作中的ABA问题
线程1读取这个内存地址存放的数值A。然后线程2先将这个内存地址存放的数值设为B,再将这个内存地址存放的数值设为A。此时,线程1依然可以执行CAS操作。但是在这个过程中并非没有问题,例如一个栈的栈顶元素发生变化后重新恢复,不代表这个栈的内部没有发生变化。
![](https://img.haomeiwen.com/i14080890/bcc15c764571e318.jpg)
(1)线程1读取栈顶指针,此时栈顶指针指向元素A,A的next等于元素B。线程1准备执行CAS操作。
(2)线程2执行CAS操作,将栈顶指针指向元素B,将A的next设为null。此时元素A处于游离状态。
(3)线程2执行CAS操作,将栈顶指针指向元素C,将B的next设为null。此时元素A和元素B都处于游离状态。
(4)线程2执行CAS操作,将栈顶指针指向元素A,将A的next设为元素C。此时元素B处于游离状态。
(5)线程1执行CAS操作,将栈顶指针指向元素B,将A的next设为null。此时代表栈顶元素的元素B处于游离状态。
3 获取Unsafe实例
通过反射可以获取Unsafe实例。
OpenJDK8 Unsafe源码:http://hg.openjdk.java.net/jdk8u/hs-dev/jdk/file/a006fa0a9e8f/src/share/classes/sun/misc/Unsafe.java
import java.lang.reflect.Field;
import sun.misc.Unsafe;
public class UnsafeDemo {
public static void main(String[] args) {
Unsafe unsafe = UnsafeDemo.getUnsafe();
System.out.println(unsafe);
}
public static Unsafe getUnsafe() {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
4 悲观锁和乐观锁
(1)悲观锁:各个用户访问数据库读取数据和更新数据时,必须先获取锁,使数据处于锁定状态,以防止其它用户更新数据。
(2)乐观锁:多个用户可以并发访问数据库,读取数据副本。用户更新数据时,比较数据库中的当前数据和数据副本,以判断其他用户是否已经更新该数据。如果二者不相等,忽略本次更新请求并提示用户更新失败。
网友评论