happens-before
原则是Java内存模型(JMM)的核心概念,用于确定程序中两个操作间的可见性和有序性。简而言之,如果一个操作A happens-before另一个操作B,那么JVM保证A操作的结果对B操作是可见的,且A操作在B之前发生。
happens-before规则详解
-
程序顺序规则:在同一个线程中,根据程序控制流,前面的操作happens-before于后续的操作。
javaint a = 1; // A操作 int b = 2; // B操作
在同一线程内,这里A操作happens-before B操作。
-
监视器锁规则:对一个锁的解锁happens-before于随后对这个锁的加锁。
javasynchronized(lock) { // ...操作A } // 另一个线程或时刻 synchronized(lock) { // ...操作B }
在这个例子中,操作A的解锁happens-before操作B的加锁。
-
volatile变量规则:对一个volatile字段的写操作happens-before于之后对这个volatile字段的读操作。
javavolatile boolean flag = false; // 线程A flag = true; // 线程B if(flag) { // ...操作 }
线程A中对
flag
的写操作happens-before线程B中对flag
的读操作。 -
线程启动规则:Thread对象的start()方法happens-before此线程的每个后续动作。
javaThread t = new Thread(() -> { // ...操作B }); // 操作A t.start();
线程的启动(操作A)happens-before线程t中的任何操作(操作B)。
-
线程终止规则:线程中的所有操作happens-before对此线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值等方式检测到线程已经终止。
-
中断规则:对线程interrupt()的调用happens-before被中断线程的检测到中断事件。
-
传递性:如果操作A happens-before操作B,且操作B happens-before操作C,那么操作A happens-before操作C。
代码示例:volatile变量规则
考虑以下代码示例,演示volatile规则的应用:
java
public class VolatileExample {
private volatile boolean ready = false;
private int number;
private class ReaderThread extends Thread {
public void run() {
while (!ready) {
Thread.yield();
}
System.out.println("The number is: " + number);
}
}
public void write() {
number = 42;
ready = true;
}
public static void main(String[] args) {
VolatileExample example = new VolatileExample();
example.new ReaderThread().start();
example.write();
}
}
这个例子中,write
方法先改变number
变量的值,然后将ready
标志设置为true。由于ready
是volatile变量,根据volatile变量规则,写入ready
的操作happens-before于读取ready
的操作,这确保了当读线程看到ready
为true时,number
变量的值对读线程是可见的。
总结
happens-before
原则是理解Java内存模型的关键,它为开发者提供了一种判断数据在多线程环境下是否能保持一致性和有序性的方法。通过遵守这些规则,开发者可以编写出更加健壮和线程安全的并发代码。