# 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格式便于技術文檔的傳播和閱讀??筛鶕枰M一步擴展具體代碼示例或性能分析章節。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。