关于面试中常见的CAS问题你知道了吗?
)
CAS
CAS的全称是 compare and swap(字面意思就是比较交换) 他是基于硬件提供的一种基础指令, 也是基于这样的指令, 就可以实现一些特殊的功能(实现锁)
针对不同的操作系统,JVM 用到了不同的 CAS 实现原理简而言之,是因为硬件予以了支持,软件层面才能做到。
我们假设内存中的原数据v,旧的预期值new,需要修改的新值tmp。
比较 new 与 v 是否相等。(比较)
如果比较相等,将 tmp 写入 v。(交换)
返回操作是否成功。
可见当多个线程同时对某个资源进行CAS操作,只能有一个线程操作成功,但是并不会阻塞其他线程,其他线程只会收到操作失败的信号。可见 CAS 其实是一个乐观锁。
CAS的使用
无锁编程
不使用锁,而是直接用CAS来保证线程安全
//线程不安全,两个线程同时修改一个变量得到的结果不一定是十万
public class Demo2 {
private static int num = 0;
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50000 ; i++) {
num++;
}
}
};
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(num);
}
}
每次的结果不同
加锁之后:
public class Demo2 {
private static int num = 0;
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50000 ; i++) {
synchronized (Demo2.class){
num++;
}
}
}
};
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(num);
}
}
100000
不加锁使用原子类
import java.util.concurrent.atomic.AtomicInteger;
public class Demo2 {
// private static int num = 0;
private static AtomicInteger num = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50000 ; i++) {
synchronized (Demo2.class){
num.getAndIncrement();//num++
//num.incrementAndGet();//++num
}
}
}
};
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(num);
}
}
CAS缺陷:ABA问题
这个问题就是加入现在有个size为0 有一个线程把他修改为1, 然后紧接着又有一个线程把他修改为0了 那此时仅仅通过CAS的比较是无法区分的
解决这个问题就需要引入额外的信息 (给变量加一个版本号 每次进行修改 都递增版本号)