并发编程 — 6.1 JUC — 非阻塞同步机制CAS

CAS的作用

在多线程并发下,可以通过加锁来保证线程安全性,但多个线程同时请求锁,而线程的挂起和恢复会有很大的开销。一些细粒度的操作,例如同步容器,操作往往只有很少代码量,如果存在锁并且线程激烈地竞争,调度的代价很大。在硬件的支持下,出现了非阻塞的同步机制,其中一种常用实现就是CAS。

CAS说明

CAS(compare and swap,比较并交换)操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值V与预期原值A相匹配,那么处理器会自动将该位置值更新为新值B。否则,处理器不做任何操作并返回V值。当多个线程尝试使用CAS同时更新一个变量,最终只有一个线程会成功,其他线程都会失败。但和使用锁不同,失败的线程不会被阻塞,而是被告之本次更新操作失败了,线程可以根据实际情况,继续重试或者跳过操作,大大减少因为阻塞而损失的性能。

Atomic原子类

Atomic原子类是CAS操作的一种体现,它分为基本数据类型原子类、数组类型原子类、引用类型原子类、字段类型原子类,其内部原理都差不多一致。例如AtomicInteger、AtomicReference、AtomicIntegerArray等等。下面以AtomicInteger为例进行简单说明。

public class MyThread implements Runnable{
    private AtomicInteger count1 = new AtomicInteger(0);
    private int count2 = 0;

    @Override
    public void run() {
        for (int i = 0; i < 100000; i++) {
            count1.incrementAndGet();
            count2++;
        }
    }

    public void printCount1() {
        System.out.println("count1: " + count1.get());
    }

    public void printCount2() {
        System.out.println("count2: " + count2);
    }
}

public static void main(String[] args){
        MyThread thread = new MyThread();
        Thread t1 = new Thread(thread, "thread1");
        Thread t2 = new Thread(thread, "thread2");
        t1.start();
        t2.start();

        while(Thread.activeCount()>2) {
            Thread.yield();
        }
        thread.printCount1();
        thread.printCount2();
    }

main函数中下面的循环是保证上面线程执行完成,然后输出结果。count1 是AtomicInteger ,而count2 是正常的int型。用两个线程一起执行20万次自增,得到的结果如下:

count1: 200000
count2: 168942

在每次执行的时候,count2的最终结果都不一致,而count1却始终是正确的结果。说明了AtomicInteger 是线程安全的。

CAS的局限性

  1. ABA问题
    根据CAS工作的基本原理,存在以下情况,变量初始值为 100,主线程通过 CAS读到了 100,接着来一个线程将这个变量改为 999,之后又一个线程又改成 100 。而轮到主线程发现 a 的值依然是 100,它视作没有人竞争过,于是修改 a 的值。这种情况,虽然 CAS 会更新成功,但是会存在潜在的问题,中途加入的线程的操作对于后一个线程根本是不可见的。而一般的解决办法是为每一次操作加上加时间戳,CAS 不仅关注变量的原始值,还关注上一次修改时间。
  2. 循环时间的额外开销
    CAS 方法一般都定义在一个循环里面,直到修改成功才会退出循环,如果在某些并发量较大的情况下,变量的值始终被别的线程修改,本线程始终在循环里做判断比较旧值,效率低下。所以说,CAS 适用于并发量不是很高的场景。
  3. 只能保证一个变量的原子操作
    CAS 只能对一个变量进行原子性操作,而锁机制则不同,获得锁之后,就可以对所有的共享变量进行修改而不会发生任何问题,因为别人没有锁不能修改这些共享变量。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值