推荐答案
在 Java 内存模型(JMM)中,happens-before 原则用于定义多线程环境中操作之间的可见性和顺序性。它确保了在一个线程中执行的某些操作的结果对另一个线程是可见的。以下是 happens-before 原则的核心规则:
- 程序顺序规则:在同一个线程中,按照程序代码的顺序,前面的操作 happens-before 后面的操作。
- 监视器锁规则:对一个锁的解锁操作 happens-before 后续对这个锁的加锁操作。
- volatile 变量规则:对一个 volatile 变量的写操作 happens-before 后续对这个变量的读操作。
- 线程启动规则:线程的
start()方法 happens-before 该线程的任何操作。 - 线程终止规则:线程中的所有操作 happens-before 其他线程检测到该线程已经终止(通过
Thread.join()或Thread.isAlive()等方法)。 - 线程中断规则:对线程
interrupt()方法的调用 happens-before 被中断线程检测到中断事件。 - 对象终结规则:一个对象的构造函数执行结束 happens-before 该对象的
finalize()方法的开始。 - 传递性:如果操作 A happens-before 操作 B,且操作 B happens-before 操作 C,那么操作 A happens-before 操作 C。
本题详细解读
1. 程序顺序规则
在单线程中,代码的执行顺序是按照程序代码的顺序执行的。JMM 保证在同一个线程内,前面的操作对后面的操作是可见的。例如:
int x = 1; // 操作 A int y = 2; // 操作 B
在这个例子中,操作 A happens-before 操作 B。
2. 监视器锁规则
当一个线程释放锁时,所有在该锁保护下的共享变量的修改对其他线程是可见的。例如:
synchronized (lock) {
x = 10; // 操作 A
}
// 操作 B在这个例子中,操作 A happens-before 操作 B。
3. volatile 变量规则
volatile 变量的写操作 happens-before 后续对该变量的读操作。例如:
// www.javascriptcn.com code example
volatile boolean flag = false;
// 线程 1
flag = true; // 操作 A
// 线程 2
if (flag) { // 操作 B
// do something
}在这个例子中,操作 A happens-before 操作 B。
4. 线程启动规则
线程的 start() 方法 happens-before 该线程的任何操作。例如:
Thread t = new Thread(() -> {
// 线程中的操作
});
t.start(); // 操作 A在这个例子中,操作 A happens-before 线程中的任何操作。
5. 线程终止规则
线程中的所有操作 happens-before 其他线程检测到该线程已经终止。例如:
Thread t = new Thread(() -> {
// 线程中的操作
});
t.start();
t.join(); // 操作 A在这个例子中,线程中的所有操作 happens-before 操作 A。
6. 线程中断规则
对线程 interrupt() 方法的调用 happens-before 被中断线程检测到中断事件。例如:
Thread t = new Thread(() -> {
if (Thread.interrupted()) { // 操作 A
// 处理中断
}
});
t.start();
t.interrupt(); // 操作 B在这个例子中,操作 B happens-before 操作 A。
7. 对象终结规则
一个对象的构造函数执行结束 happens-before 该对象的 finalize() 方法的开始。例如:
class MyClass {
@Override
protected void finalize() throws Throwable {
// 终结操作
}
}
MyClass obj = new MyClass(); // 操作 A在这个例子中,操作 A happens-before finalize() 方法的执行。
8. 传递性
如果操作 A happens-before 操作 B,且操作 B happens-before 操作 C,那么操作 A happens-before 操作 C。例如:
int x = 1; // 操作 A
synchronized (lock) {
x = 2; // 操作 B
}
int y = x; // 操作 C在这个例子中,操作 A happens-before 操作 B,操作 B happens-before 操作 C,因此操作 A happens-before 操作 C。