文章目录
- 线程间通信
-
- 线程间通信的核心问题
- [volatile 关键字](#volatile 关键字)
-
- [1. 核心特性](#1. 核心特性)
- [2. 使用限制](#2. 使用限制)
- [3. 示例](#3. 示例)
- [synchronized 关键字](#synchronized 关键字)
-
- [1. 核心特性](#1. 核心特性)
- [2. 示例](#2. 示例)
- [volatile 与 synchronized 的对比](#volatile 与 synchronized 的对比)
- [Volatile 和 Synchronized 最佳实践](#Volatile 和 Synchronized 最佳实践)
线程间通信
线程间通信的核心问题
多个线程通过共享内存实现信息交换,但需解决以下问题:
- 可见性:线程修改变量后其他线程能否立即感知。
- 原子性:操作是否不可分割,避免数据不一致。
- 有序性:代码执行顺序是否符合预期。
volatile 关键字
1. 核心特性
-
可见性保证 :所有线程直接访问共享内存中的变量值,而非本地缓存。
-
写操作:强制将修改后的值刷新到主内存。
-
读操作:强制从主内存读取最新值。
-
-
禁止指令重排序:通过内存屏障限制编译器和处理器的重排序。
2. 使用限制
-
不保证原子性 :仅适用于单次读/写操作,无法处理复合操作(如
i++
)。 -
典型场景:
-
状态标志 (如
volatile boolean on = true
)。 -
配合 CAS 操作实现无锁并发(如
AtomicInteger
内部实现)。
-
3. 示例
java
public class StatusMonitor {
private volatile boolean running = true; // 状态标志
public void shutdown() {
running = false; // 修改后对所有线程可见
}
public void doWork() {
while (running) { // 实时读取共享内存的值
// 执行任务
}
}
}
synchronized 关键字
1. 核心特性
-
原子性 & 排他性:同一时刻只允许一个线程进入同步代码。
-
隐式锁机制:通过锁对象实现同步(锁粒度可以是实例对象、Class 对象或自定义对象)。
-
可见性保证:线程退出同步代码时,修改的变量值强制刷新到主内存。
synchronized 无法完全禁止内部指令重排序 ,但通过临界区的内存屏障和线程互斥访问机制,对外部线程表现为有序性。
在需要严格禁止重排序的高并发场景中(如单例初始化),必须结合 volatile 来补充有序性保证。
2. 示例
java
public class Counter {
private int count = 0;
public synchronized void increment() { // 普通同步方法
count++; // 原子操作
}
public static synchronized void staticMethod() { // 静态同步方法
// 操作共享资源
}
public void blockSync() {
synchronized (this) { // 同步块
count--;
}
}
}
volatile 与 synchronized 的对比
特性 | volatile | synchronized |
---|---|---|
可见性 | 保证 | 保证 |
原子性 | 仅支持单个读/写操作 | 支持代码块级原子性 |
排他性 | 无 | 有(同一时刻仅一个线程访问) |
性能消耗 | 较低(仅内存屏障) | 较高(涉及锁竞争与上下文切换) |
适用场景 | 状态标志、双重检查锁(DCL) | 复杂操作保护(如转账、计数等) |
Volatile 和 Synchronized 最佳实践
- 双重检查锁定(Double-Checked Locking):
java
public class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton(); // volatile 防止指令重排序
}
}
}
return instance;
}
}
volatile
在此阻止 JVM 重排序初始化步骤(分配内存与对象构造),确保线程安全。