返回

原子变量及 CAS

后端

原子变量顾名思义,就是具有原子性的变量。原子性是指变量操作不会被中断,无论有多少线程同时操作该变量,都只能由一个线程对其进行操作。

在 Java 中,原子变量是通过 CAS(Compare-And-Swap)操作来实现的。CAS 操作的基本原理是:比较变量的当前值是否等于预期值,如果是则更新变量的值,否则不更新。

CAS 操作的格式如下:

boolean compareAndSet(int expectedValue, int newValue)
  • expectedValue: 预期的值。
  • newValue: 如果变量的当前值等于 expectedValue,则将变量的值更新为 newValue。

CAS 操作的实现步骤如下:

  1. 线程 A 将变量的当前值读入寄存器中。
  2. 线程 A 将 expectedValue 与寄存器中的值进行比较。
  3. 如果 expectedValue 等于寄存器中的值,则线程 A 将 newValue 写入寄存器中。
  4. 线程 A 将寄存器中的值写入变量中。

如果在步骤 2 中,线程 A 发现 expectedValue 不等于寄存器中的值,则说明变量的值已被其他线程修改。此时,线程 A 需要重新获取变量的当前值,并再次执行 CAS 操作。

CAS 操作保证了原子性 ,因为它只允许一个线程对变量进行操作。如果其他线程试图在同一时间访问变量,它们将被阻塞,直到第一个线程完成操作。

CAS 操作的应用场景非常广泛 ,比如:

  • 实现锁: CAS 操作可以用来实现锁,从而保证共享资源的独占访问。
  • 计数器: CAS 操作可以用来实现计数器,从而保证对共享计数器的并发访问。
  • 原子更新: CAS 操作可以用来原子地更新变量的值,从而保证更新操作的正确性。

示例:

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {

    private static AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) {
        // 创建多个线程,同时对count进行加一操作
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    // 使用 CAS 操作对count进行加一操作
                    count.incrementAndGet();
                }
            }).start();
        }

        // 等待所有线程执行完成
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 打印count的最终值
        System.out.println("count = " + count.get());
    }
}

在上面的示例中,我们使用 CAS 操作来对共享变量 count 进行加一操作。由于 CAS 操作保证了原子性,因此我们可以保证 count 的值始终是正确的。

总结

CAS 操作是一种非常重要的并发编程技术,它可以用来实现原子变量、锁、计数器等并发数据结构。CAS 操作的广泛应用,使得 Java 在处理并发问题时更加高效和可靠。