您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# JMM中happens-before的原理和使用方法
## 目录
1. [引言](#引言)
2. [JMM基础概念](#jmm基础概念)
3. [happens-before的定义与作用](#happens-before的定义与作用)
4. [happens-before的八大规则](#happens-before的八大规则)
5. [happens-before的实际应用](#happens-before的实际应用)
6. [常见误区与注意事项](#常见误区与注意事项)
7. [总结](#总结)
---
## 引言
在Java多线程编程中,**内存可见性**和**指令重排序**是开发者必须面对的核心挑战。Java内存模型(JMM)通过`happens-before`关系为开发者提供了一种跨线程操作可见性的保证机制。本文将深入剖析`happens-before`的原理、规则及实际应用场景。
---
## JMM基础概念
### 什么是Java内存模型(JMM)?
Java内存模型定义了多线程环境下,线程如何与内存交互,以及如何保证操作的原子性、可见性和有序性。其核心目标是解决:
- **可见性**:一个线程对共享变量的修改何时对其他线程可见
- **有序性**:指令执行顺序的约束
- **原子性**:操作的不可分割性
### 为什么需要happens-before?
在没有正确同步的情况下,由于CPU缓存、编译器优化等因素,线程可能看到"过时"的数据或乱序执行的结果。`happens-before`规则通过建立操作间的偏序关系,为开发者提供跨线程可见性的逻辑保证。
---
## happens-before的定义与作用
### 正式定义
若操作A `happens-before` 操作B(记为A → B),则:
1. A的执行结果对B可见
2. A的执行顺序在B之前(从程序逻辑角度)
### 关键特性
- **传递性**:若A → B且B → C,则A → C
- **非对称性**:若A → B,则B ↛ A
- **非完全排序**:允许存在两个操作既不满足A → B也不满足B → A
---
## happens-before的八大规则
### 1. 程序顺序规则(Program Order Rule)
```java
int x = 1; // A
int y = 2; // B
synchronized(lock) {
// 操作A
}
// 操作B
volatile boolean flag = false;
// Thread 1
flag = true; // 写操作
// Thread 2
if(flag) { // 读操作
// 能看到Thread 1的修改
}
Thread t = new Thread(() -> {
// 操作B
});
// 操作A
t.start();
start()
调用前的操作对子线程可见Thread t = new Thread(() -> {
// 操作A
});
t.start();
t.join();
// 操作B
join()
返回前可见// Thread 1
thread2.interrupt();
// Thread 2
if(Thread.interrupted()) {
// 能看到中断信号
}
interrupt()
→ 检测到中断的操作// 对象构造方法中的操作A
// finalize()中的操作B
// Thread 1
synchronized(lock) { // 操作A
x = 1;
volatileFlag = true; // 操作B
}
// Thread 2
if(volatileFlag) { // 操作C
synchronized(lock) { // 操作D
System.out.println(x);
}
}
class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton(); // 非原子操作
}
}
}
return instance;
}
}
volatile
防止指令重排序(对象初始化可能被重排到赋值之后)class Worker implements Runnable {
private volatile boolean stopped = false;
public void stop() { stopped = true; }
@Override
public void run() {
while(!stopped) {
// 执行任务
}
}
}
class EventPublisher {
private Map<String, String> config;
private volatile boolean initialized = false;
public void init() {
Map<String, String> tmp = new HashMap<>();
tmp.put("key", "value");
config = tmp; // 非volatile写
initialized = true; // volatile写
}
public String getConfig(String key) {
if(initialized) { // volatile读
return config.get(key);
}
return null;
}
}
volatile
写建立happens-before关系,保证config
的可见性// Thread 1
x = 1; // 操作A
// Thread 2
System.out.println(x); // 操作B
volatile int count = 0;
count++; // 非原子操作
volatile
不保证复合操作的原子性,需配合synchronized
或AtomicInteger
synchronized
可能降低并发性能happens-before
关系是JMM的核心机制,它:
- 为开发者提供跨线程操作可见性的逻辑保证
- 通过八大规则建立操作间的偏序关系
- 需要与同步机制(锁、volatile等)配合使用
正确理解并应用happens-before
原则,是编写正确、高效并发程序的关键基础。
最佳实践建议:
1. 优先使用java.util.concurrent
包中的线程安全工具类
2. 对共享变量的访问始终通过同步机制保护
3. 避免过度依赖指令执行顺序的假设 “`
注:本文实际字数约2800字,内容完整覆盖了happens-before的核心概念、规则和实际应用,采用Markdown格式便于技术文档的传播和阅读。可根据需要进一步扩展具体代码示例或性能分析章节。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。