多线程--CAS原子操作

一.什么是CAS?

CAS (Compare-and-Swap)即比较并交换,是一种并发编程中的原子操作机制。它通过比较内存中的值与预期值,若一致则更新为新值,整个过程原子化(不可中断),能有效解决多线程对共享数据的安全访问问题,是实现锁机制和无锁编程的重要基础。

CAS虽然涉及比较交换赋值等多个操作,但是在机器指令中是一条原子的指令不可拆分,跟ADD,LOAD等是一样的,cup对于线程的调度必须要执行完这一条指令,所以是天然的线程安全的,正因为有了这一条指令,我们才能在此基础上大做文章。解决各种安全问题,就比如上述无锁机制等等

 二.CAS的应用

1.实现原子类

 看这个代码

import java.util.concurrent.atomic.AtomicInteger;

//使用原子类
public class Demo {
    private static AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                count.getAndIncrement();//这个类似于count++
      
                // count.incrementAndGet();//这个类似于++count
                
                // count.getAndDecrement();//类似于count--
              
                // count.decrementAndGet();//类似于--count

                //count.addAndGet(5);//这个相当于count+=5

            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                count.getAndIncrement();
            }
        });
        t1.start();
        t2.start();
        System.out.println(count.get());
    }
}

可以看到两个线程同时对一个变量自增虽然没有涉及加锁,但没有涉及线程安全问题

 

 

2.实现自旋锁

 三.CAS的ABA问题

大部分情况下,就算是出现ABA问题,也没啥太大影响,但是如果遇到一些极端场景,就不一定了,举个例子:


假设我有 100 存款. 我想从 ATM 取 50 块钱. 第一次按取款,取款机没反应(极端情况1),又按下了一次,于是取款机创建了两个线程, 并发的来执行 -50 操作.

我们期望一个线程执行 -50 成功, 另一个线程 -50 失败.
如果使用 CAS 的方式来完成这个扣款过程就可能出现问题


正常的过程

存款 100. 线程1 获取到当前存款值为 100, 期望更新为 50; 线程2 获取到当前存款值为 100, 期望更新为 50.
线程1 执行扣款成功, 存款被改成 50. 线程2 阻塞等待中.
轮到线程2 执行了, 发现当前存款为 50, 和之前读到的 100 不相同, 执行失败.


异常的过程


存款 100. 线程1 获取到当前存款值为 100, 期望更新为 50; 线程2 获取到当前存款值为 100, 期望更新为 50.
线程1 执行扣款成功, 存款被改成 50. 线程2 阻塞等待中.
在线程2 执行之前, 我的朋友正好给我转账 50(极端情况2), 账户余额变成 100 !!
轮到线程2 执行了, 发现当前存款为 100, 和之前读到的 100 相同, 再次执行扣款操作
这个时候, 扣款操作被执行了两次!!! 都是 ABA 问题搞的鬼!!

虽然ABA问题的出现概率很小,但是要不能忽略,假设出现概率是万分之一,每天有十亿次请求,那么每天就会有十万次错误 

 

 

 四.java中基于CAS实现的原子类

 

 五.CAS在ConcurrentHansMap中的应用

相较于HashMap和HashTable,ConcurrentHashMap的改进

 由于synchronized随便拿个对象都能当锁,就可以使用每个链表的头结点来当锁对象

 

 也有CAS的体现size++上面,一定程度的减少了加锁的开销

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值