Happens-before là đảm bảo của Java Memory Model (JMM): nếu action A happens-before action B → mọi thay đổi của A chắc chắn visible với B.
Không có happens-before, JVM/CPU có thể reorder hoặc cache write → thread khác không thấy thay đổi.
Các quy tắc tạo happens-before:
- Program order: trong cùng thread, statement trước happens-before statement sau.
- Monitor lock: unlock(lock) happens-before lock(lock) tiếp theo trên cùng lock.
- Volatile: write volatile happens-before read tiếp theo của cùng biến.
- Thread start: thread.start() happens-before mọi action trong thread đó.
- Thread join: mọi action trong thread happens-before thread.join() trả về.
- Transitivity: A → B và B → C → A → C.
int data = 0;
volatile boolean ready = false;
// Thread A
data = 42; // 1
ready = true; // 2 — volatile write
// Thread B
if (ready) { // 3 — volatile read
use(data); // 4 — chắc chắn thấy 42
}→ 1 happens-before 2 (program order); 2 happens-before 3 (volatile); 3 happens-before 4 (program order) → 1 happens-before 4.
JVM implement bằng memory barrier (CPU instruction flush/reload cache). Đây là nền tảng để lập trình viên suy luận correctness mà không cần hiểu chi tiết CPU cache.
Happens-before is a Java Memory Model (JMM) guarantee: if action A happens-before action B → A's effects are guaranteed visible to B.
Without happens-before, the JVM/CPU may reorder or cache writes → other threads do not see the change.
Rules that establish happens-before:
- Program order: within a thread, earlier statements happen-before later ones.
- Monitor lock: unlock(lock) happens-before the next lock(lock) on the same lock.
- Volatile: a volatile write happens-before any subsequent read of the same variable.
- Thread start: thread.start() happens-before any action in that thread.
- Thread join: every action in a thread happens-before thread.join() returns.
- Transitivity: A → B and B → C → A → C.
int data = 0;
volatile boolean ready = false;
// Thread A
data = 42; // 1
ready = true; // 2 — volatile write
// Thread B
if (ready) { // 3 — volatile read
use(data); // 4 — guaranteed to see 42
}→ 1 happens-before 2 (program order); 2 happens-before 3 (volatile); 3 happens-before 4 (program order) → 1 happens-before 4.
The JVM implements this with memory barriers (CPU instructions to flush/reload caches). This is the foundation for reasoning about correctness without diving into CPU cache details.