自学内容网 自学内容网

[JAVAEE] 面试题(二) - CAS 和 原子类

目录

一. CAS的实现原理

1.1 伪代码分析

1.2 底层实现 

二. CAS 操作示例

三. ABA问题

四. 原子类

4.1 使用原子类的目的

4.2 原子类的使用示例

五. 总结


一. CAS的实现原理

CAS(compare and swap 比较和交换)是一种用于实现无锁并发的技术.

1.1 伪代码分析

    // 伪代码
    boolean CAS(address, expectValue, swapValue) {
        if (&address == expectValue) {
            &address = swapValue;
            return true;
        }
        return false;
    }

&address: 需要修改的值.

expectValue: 预期的值.

swapValue: 新值, 需要赋值给&address的值.

核心思想: 比较当前需要修改的值和预期的值是否相同, 如果相同, 就用新值替换需要修改的值.

1.2 底层实现 

CAS无锁并发技术底层是靠C语言依赖的操作系统的原子操作来实现原子性的. 即在这个过程中不会被其他线程打断(CAS可以理解为是一个赋值操作, 这是原子性的, 不会产生线程安全问题).


二. CAS 操作示例

假设有一个整数变量count, 初始值为0, 现在有A, B两个线程同时对count进行+1操作.(使用CAS无锁并发技术)

1. 线程A读取变量count的值, 得到0.

2. 线程B读取变量count的值, 得到0.

3. 线程A将变量count的值与预期的值0进行比较, 相等, 将count的值增加为1.

4. 线程B将变量count的值与预期的值0进行比较, 不相等(count的值已经被线程A增加为1), 则重试.

5. 线程B重新读取变量count的值, 得到1.

6. 线程B将变量count的值与预期的值1进行比较, 相等, 将count的值增加为2.

最终, count的值为2.


三. ABA问题

假设有两个线程, 线程1使用CAS技术将val的值从A修改成B, 又把val的值从B修改成A. 线程2通过CAS技术判断线程1没有对val的值进行修改, 于是线程2再次修改val的值(实际上不需要修改). 这就是 ABA 问题.

解决:

在CAS操作的时候对val加版本号.

A 1.0

B 2.0

A 3.0

java中的 AtomicStampedReference类 解决了ABA问题.


四. 原子类

java中的原子类在 java.util.concurrent.atomic 包中.

4.1 使用原子类的目的

为了不加锁, 提高程序运行效率.

4.2 原子类的使用示例

实现一个无锁的计数器.

    static AtomicInteger count = new AtomicInteger();
    public static void main(String[] args) throws InterruptedException{
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                count.getAndIncrement();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                count.getAndIncrement();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count.get());
    }


五. 总结

1. CAS(compare and swap) 是一种无锁并发技术.

2. CAS的伪代码分析: 将需要修改的值和预期的值进行比较, 如果相等, 就用新值替换需要修改的值.

3. CAS的底层实现: CAS底层是靠C语言依赖的操作系统的原子操作来实现的原子性,(本质上是赋值操作, 是原子性的, 是线程安全的.)

4. ABA问题, 解决(对CAS操作需要修改的值加版本号).

5. 使用原子类的目的.(为了避免加锁操作, 提高程序运行效率).


原文地址:https://blog.csdn.net/nmbg11/article/details/143356376

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!