Appearance
源码: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 保证互斥与原子性)
*/
}
}