我们在cas也就是Compare-And-Swap,简写为cas,我们先不去想什么是cas啊,我们先来想
我们在多线程情况下要修改一个变量的话,在不加锁的情况线程一旦开始就要一直运行到结束,这时候变量就会出现线程安全的问题,比较典型的是票的超卖问题,但是如果我们加锁的话,因为涉及到线程的上下文切换,阻塞等就不可避免的会出现效率变低的问题。
而cas 就根据乐观锁的思想,对一个变量的修改,来进行 不加锁保证效率的情况下,来对该变量进行 安全的并发修改
并发代码
我们来看下面的代码
这是一个接口
interface Account {
Integer getBalance();
void withDraw(Integer downBalance);
}
然后这是接口的实现类
class CasAccount implements Account {
private AtomicInteger balance;
public CasAccount(Integer balance) {
this.balance = new AtomicInteger(balance);
}
@Override
public Integer getBalance() {
return balance.get();
}
@Override
public void withDraw(Integer downBalance) {
while (true) {
int cur = balance.get();
int nextBalance = cur - downBalance;
if (balance.compareAndSet(cur, nextBalance)) {
break;
}
}
}
}
接下来是我们的多线程并发修改 balance 的值
public static void main(String[] args) {
CasAccount casAccount = new CasAccount(1000);
ArrayList<Thread> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
list.add(new Thread(new Runnable() {
@Override
public void run() {
casAccount.withDraw(10);
}
}));
}
list.forEach(Thread::start);
list.forEach(t-> {
try {
t.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
System.out.println(casAccount.getBalance());
}
我们下面着重来看下面一段代码的逻辑
class CasAccount implements Account {
private AtomicInteger balance;
public CasAccount(Integer balance) {
this.balance = new AtomicInteger(balance);
}
@Override
public void withDraw(Integer downBalance) {
while (true) {
int cur = balance.get();
int nextBalance = cur - downBalance;
if (balance.compareAndSet(cur, nextBalance)) {
break;
}
}
}
}
在该实现类中,我们用的balance 是 原子类
AtomicInteger
修饰的,他的底层就是用硬件来保证原子性,而不是加锁。
我们分析这段代码
- 线程1 进入循环,这时候获得balance的值 为1000,这时候cur设置为1000,然后 我们扣减余款10,这时候 nextBalance 被设置为990,然后 调用该 compareandset方法的时候,如果cur的值还等于原来的balance的值1000,我们会把该 类中私有的 AtomicInteger 类型的 balance 值 修改为 nextBanlce 990,这时候跳出循环,该线程结束 ,当然这是理想的情况
第一次分析 当然是 正常线程的正常修改的情况下,我们接下来分析其他线程修改的情况,当线程1进入循环,获得cur值为1000,然后nextbalance值为990,这时候来了线程二抢到cpu执行权,直接完成了修改操作,把balance值改为了990,这时候线程1继续运行,在atomicinterger.compareandset方法 比较私有化的balance值跟cur的1000比对,发现不对,这时候会继续返回false,然后重新进行循环.
这就是cas的实现
cas配合volatile
,然而这种实现 体现的是无锁并发,无阻塞式并发,当我们一个资源竞争的非常激烈的时候,这种一直循环带来的资源消耗也是比较大的。所以cas适用于线程数少,多核cpu的情况。而cas是怎么让一个资源在多个线程下可见的,他也是使用了volatile 让资源在线程中可见
编辑