volatile修饰复合操作安全吗
不安全。java中的volatile关键字只能保证变量的可见性和禁止指令重排序,但不具备原子性。对于像i++、count += 1或“读取-修改-写入”这类复合操作,多个线程同时执行时仍会发生数据竞争,导致最终结果与预期不符。

为什么i++在多线程下会出错
因为i++在字节码层面被分解为三个步骤:从主内存加载变量值到工作内存、在寄存器中进行加1运算、将新值写回主内存。即使i是volatile的,这三个步骤也不是原子的。当两个线程同时读取到相同的旧值并分别加1后写回,其中一个线程的修改会被覆盖,造成计数丢失。

public class VolatileCounter {
private volatile int count = 0;
public void increment() {
// 非原子操作:read -> modify -> write
count++;
}
public static void main(String[] args) throws InterruptedException {
VolatileCounter counter = new VolatileCounter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count: " + counter.count);
// 预期输出应为 20000,但实际通常小于 20000
}
}
如何正确实现线程安全的复合操作
要解决上述问题,可以使用java.util.concurrent.atomic包下的原子类(如AtomicInteger),或者使用synchronized关键字/显式锁来保证操作的原子性。AtomicInteger内部利用CAS(Compare-And-Swap)硬件指令实现无锁的原子更新,既保证了安全性,又比传统锁具有更好的并发性能。
立即学习“Java免费学习笔记(深入)”;

import java.util.concurrent.atomic.AtomicInteger;
public class AtomicCounter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
// 原子操作:compare and set
count.incrementAndGet();
}
public static void main(String[] args) throws InterruptedException {
AtomicCounter counter = new AtomicCounter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count: " + counter.count.get());
// 预期输出始终为 20000
}
}


















