一、引言:为什么需要三大特性?
在多线程环境中,多个线程共享内存,若不加控制,会出现以下问题:
- 原子性破坏:
i++操作被拆分为'读 - 改 - 写',导致结果错误; - 可见性缺失:线程 A 修改变量,线程 B 仍读取旧值;
- 有序性混乱:编译器/CPU 指令重排序导致逻辑错乱(如 DCL 单例失效)。
Java 内存模型(JMM)通过 三大特性保障并发安全。
Java 多线程并发安全依赖内存模型(JMM)保障的三大特性:原子性、可见性和有序性。原子性通过 synchronized、ReentrantLock、原子类及 StampedLock 实现;可见性由 volatile、synchronized 及 final 字段保证;有序性通过禁止指令重排序(如 DCL 单例中的 volatile)和监视器锁维护。文章详细解析了各机制的底层原理(如 Monitor、AQS、CAS、内存屏障)及适用场景,并提供最佳实践建议。
在多线程环境中,多个线程共享内存,若不加控制,会出现以下问题:
i++ 操作被拆分为'读 - 改 - 写',导致结果错误;Java 内存模型(JMM)通过 三大特性保障并发安全。
⚠️ 注意:'一致性'不是 Java 并发三大特性的标准术语,常见于数据库(ACID)或分布式系统(CAP)。
| 特性 | 定义 | 核心问题 |
|---|---|---|
| 原子性 | 操作不可分割,要么全部执行成功,要么完全不执行 | 复合操作被线程交错打断 |
| 可见性 | 一个线程修改共享变量后,其他线程能立即看到最新值 | 工作内存与主内存不同步 |
| 有序性 | 程序执行顺序应符合代码编写顺序 | 编译器/CPU 指令重排序 |
synchronized —— JVM 内置锁public class SynchronizedExample {
private int count = 0;
public synchronized void increment() {
count++; // 非原子操作,需同步保护
}
public static void main(String[] args) throws InterruptedException {
SynchronizedExample e = new SynchronizedExample();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) e.increment();
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) e.increment();
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count: " + e.count); // 输出 2000
}
}
monitorenter:进入同步块时获取锁;monitorexit:退出时释放锁。锁升级路径:
无锁 → 偏向锁(单线程优化) → 轻量级锁(自旋) → 重量级锁(OS 阻塞)
ReentrantLock —— 显式可重入锁import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private int count = 0;
private final ReentrantLock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock(); // 必须在 finally 中释放
}
}
public static void main(String[] args) throws InterruptedException {
ReentrantLockExample e = new ReentrantLockExample();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) e.increment();
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) e.increment();
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count: " + e.count); // 输出 2000
}
}
volatile int state(锁状态)、Node head/tail(CLH 双向等待队列)。state 从 0 → 1;Node 入队,并调用 LockSupport.park() 阻塞;state 减 1;LockSupport.unpark())。state 递增)。Condition)。AtomicInteger)import java.util.concurrent.atomic.AtomicInteger;
public class AtomicExample {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet(); // 原子自增
}
public static void main(String[] args) throws InterruptedException {
AtomicExample e = new AtomicExample();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) e.increment();
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) e.increment();
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count: " + e.count.get()); // 输出 2000
}
}
compareAndSwapInt(),利用 CPU 原子指令(如 x86 的 LOCK CMPXCHG)。private volatile int value,天然具备可见性与部分有序性。AtomicStampedReference 解决。CAS(Compare-And-Swap):
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
StampedLock —— 乐观读写锁import java.util.concurrent.locks.StampedLock;
public class StampedLockExample {
private double x = 0, y = 0;
private final StampedLock sl = new StampedLock();
void move(double dx, double dy) {
long stamp = sl.writeLock();
try {
x += dx;
y += dy;
} finally {
sl.unlockWrite(stamp);
}
}
double distanceFromOrigin() {
long stamp = sl.tryOptimisticRead(); // 乐观读
double currentX = x, currentY = y;
if (!sl.validate(stamp)) { // 检查是否被写入
stamp = sl.readLock(); // 升级为悲观读
try {
currentX = x;
currentY = y;
} finally {
sl.unlockRead(stamp);
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}
public static void main(String[] args) {
StampedLockExample obj = new StampedLockExample();
obj.move(3, 4);
System.out.println("Distance: " + obj.distanceFromOrigin()); // 输出 5.0
}
}
long stamp 代替 int state,低 7 位表示锁模式,高位为版本号。validate(stamp));volatile —— 轻量级可见性保障public class VolatileVisibilityExample {
private volatile boolean running = true; // volatile 保证可见性
public void stop() {
running = false;
}
public void runTask() {
while (running) {
System.out.println("Working...");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
break;
}
}
System.out.println("Task stopped.");
}
public static void main(String[] args) throws InterruptedException {
VolatileVisibilityExample task = new VolatileVisibilityExample();
Thread worker = new Thread(task::runTask);
worker.start();
Thread.sleep(2000);
task.stop(); // 主线程停止任务
worker.join();
}
}
❗ 若去掉
volatile,worker线程可能永远看不到running = false,导致死循环。
StoreStore + StoreLoad,禁止写之前的操作重排到写之后;LoadLoad + LoadStore,禁止读之后的操作重排到读之前。i++ 仍需锁或原子类。synchronized 保证可见性SynchronizedExample)final 字段的可见性public class FinalFieldExample {
private final int x;
private final int y;
public FinalFieldExample(int x, int y) {
this.x = x;
this.y = y; // 构造完成后对所有线程可见
}
public int sum() {
return x + y; // 无需同步,安全
}
public static void main(String[] args) {
FinalFieldExample obj = new FinalFieldExample(3, 4);
new Thread(() -> {
System.out.println("Sum in thread: " + obj.sum()); // 输出 7
}).start();
}
}
volatile 禁止重排序(DCL 单例)public class DoubleCheckedLockingSingleton {
// 必须加 volatile!否则可能返回未完全初始化的对象
private volatile static DoubleCheckedLockingSingleton instance;
private DoubleCheckedLockingSingleton() {}
public static DoubleCheckedLockingSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckedLockingSingleton.class) {
if (instance == null) {
instance = new DoubleCheckedLockingSingleton(); // 关键:防止重排序
}
}
}
return instance;
}
public void doSomething() {
System.out.println("Singleton working...");
}
public static void main(String[] args) {
DoubleCheckedLockingSingleton s1 = getInstance();
DoubleCheckedLockingSingleton s2 = getInstance();
System.out.println(s1 == s2); // true
s1.doSomething();
}
}
instance 指向内存地址。1 → 3 → 2,导致其他线程拿到未初始化对象。instance = new ... 写操作后插入 StoreStore 屏障;synchronized 保证有序性| 方案 | 原子性 | 可见性 | 有序性 | 底层机制 | 适用场景 |
|---|---|---|---|---|---|
synchronized | ✅ | ✅ | ✅ | Monitor(对象头 Mark Word) | 通用同步,复合操作 |
ReentrantLock | ✅ | ✅ | ✅ | AQS + CAS + CLH 队列 | 需要高级控制(超时、公平等) |
| 原子类 | ✅(单变量) | ✅ | ✅ | CAS + volatile + Unsafe | 单变量无锁并发 |
StampedLock | ✅ | ✅ | ✅ | 改进 AQS + 乐观读 | 读多写少高性能场景 |
volatile | ❌ | ✅ | ✅(部分) | 内存屏障 + 缓存一致性协议 | 状态标志、DCL 单例 |
final | ❌ | ✅(构造后) | ✅(构造阶段) | JMM final 语义 | 不可变对象 |
volatile boolean flagAtomicInteger 或 LongAdder(高并发分段累加)synchronized(简单)或 ReentrantLock(灵活)StampedLockfinal 字段 + 构造函数安全初始化| 概念 | 说明 |
|---|---|
| JMM(Java Memory Model) | 定义线程与主内存交互规则 |
| happens-before | JMM 核心规则,保证操作可见性与有序性 |
| CAS(Compare-And-Swap) | CPU 原子指令,无锁并发基础 |
| AQS | JUC 锁框架基石,基于 CLH 队列 |
| 内存屏障 | 禁止指令重排序的硬件/编译器指令 |
💡 口诀记忆:原(原子性)可(可见性)有(有序性)——Java 并发三基石。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online