Skip to content

源码:labs/java/runtime-concurrency/volatile-vs-atomic-vs-lock/src/VolatileVsAtomicVsLock.java

  • 原始路径:labs/java/runtime-concurrency/volatile-vs-atomic-vs-lock/src/VolatileVsAtomicVsLock.java
  • 类型:java
java
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 本实验对比 volatile、AtomicInteger、synchronized/Lock 在并发场景下的表现。
 * 包含两个典型测试:
 * 1. 状态标记控制(volatile 适用场景):多线程读取,主线程单次修改控制开关。
 * 2. 高并发自增计数(volatile 不适用场景):展示 volatileCount 丢失更新问题,对比 AtomicInteger 和 synchronized 的正确性。
 */
public class VolatileVsAtomicVsLock {

    // ----------------- 场景 1:状态标记位(volatile 适用) -----------------
    // 使用 volatile 保证主线程写状态后,子线程能够立即可见并安全退出
    private static volatile boolean runningFlag = true;

    // ----------------- 场景 2:并发计数器(volatile 不适用) -----------------
    private static volatile int volatileCount = 0;
    private static final AtomicInteger atomicCount = new AtomicInteger(0);
    private static int syncCount = 0;
    private static final Object lock = new Object();

    public static void main(String[] args) throws Exception {
        System.out.println("====== 场景 1:volatile 适用 - 状态标记位/停止开关 ======");
        testVolatileFlag();

        System.out.println("\n====== 场景 2:volatile 不适用 - 高并发自增计数 ======");
        testCounterComparison();
    }

    /**
     * 测试说明:volatile 适合状态标记控制(单次写,多次读)
     */
    static void testVolatileFlag() throws Exception {
        Thread worker = new Thread(() -> {
            int count = 0;
            while (runningFlag) { // 循环读取 volatile 变量,保证能看到主线程修改的值
                count++;
            }
            System.out.println("【状态标记测试】工作线程接收到停止信号,退出循环!本地计数累加次数:" + count);
        });

        worker.start();
        Thread.sleep(10); // 让工作线程跑一会儿

        runningFlag = false; // 主线程修改 volatile 变量(单次写)
        worker.join();
        System.out.println("【状态标记测试】主线程成功让工作线程停止运行。");

        /* 静态阅读参考输出:
         * ====== 场景 1:volatile 适用 - 状态标记位/停止开关 ======
         * 【状态标记测试】工作线程接收到停止信号,退出循环!本地计数累加次数:20243084
         * 【状态标记测试】主线程成功让工作线程停止运行。
         */
    }

    /**
     * 测试说明:高并发自增计数(10 个线程,每个自增 1000 次,期望总数 10,000)
     * - volatileCount:出现数据丢失(因为 count++ 包含了 读-改-写 3 步,不是原子操作)
     * - atomicCount:CAS 保证原子性,结果必定为 10000
     * - syncCount:锁保证原子性与互斥,结果必定为 10000
     */
    static void testCounterComparison() throws Exception {
        int threadCount = 10;
        int incrementsPerThread = 1000;
        int expectedTotal = threadCount * incrementsPerThread;

        ExecutorService pool = Executors.newFixedThreadPool(threadCount);
        CountDownLatch latch = new CountDownLatch(threadCount);

        for (int i = 0; i < threadCount; i++) {
            pool.execute(() -> {
                for (int j = 0; j < incrementsPerThread; j++) {
                    // 1. volatile 复合操作(非原子)
                    volatileCount++;

                    // 2. AtomicInteger(CAS 无锁原子操作)
                    atomicCount.incrementAndGet();

                    // 3. synchronized(加锁保障原子性)
                    synchronized (lock) {
                        syncCount++;
                    }
                }
                latch.countDown();
            });
        }

        latch.await();
        pool.shutdown();

        System.out.println("期待结果 (Expected Count)   : " + expectedTotal);
        System.out.println("volatileCount 实际结果      : " + volatileCount + " (由于非原子操作导致更新丢失)");
        System.out.println("atomicCount 实际结果        : " + atomicCount.get() + " (CAS 保证原子性)");
        System.out.println("syncCount 实际结果          : " + syncCount + " (锁保证原子性与互斥)");

        /* 静态阅读参考输出(高并发测试实际运行效果):
         * ====== 场景 2:volatile 不适用 - 高并发自增计数 ======
         * 期待结果 (Expected Count)   : 10000
         * volatileCount 实际结果      : 9954 (小于 10000,说明 volatile 无法保证自增原子性,发生更新丢失)
         * atomicCount 实际结果        : 10000 (精确等于 10000,CAS 保证原子性)
         * syncCount 实际结果          : 10000 (精确等于 10000,synchronized 保证互斥与原子性)
         */
    }
}