什么是happens-before原则 ?
一、定义
happens-before原则是一种用于描述多线程程序中操作执行顺序的规则。它是Java内存模型(Java Memory Model,JMM)的一部分:
如果一个操作 A “happen-before” 另一个操作 B,那么 A 的结果对 B 是可见的。这个概念是理解线程间内存可见性的关键。
举一个例子,如以下代码:
public class ThreadStartExample {
    private int startValue = 10;
    public void startNewThread() {
        startValue +=1;
        new Thread(() -> {
            int localValue = startValue;  
        }).start();
    }
}
有两个线程,一个写startValue,一个读startValue,但是我们并没有用synchronized加锁,也没有用volatile修饰,那么JVM是如何保证,在主线程中修改startValue的操作在子线程中是可见的呢 ?
这其实就是happens-before原则发挥的作用了。但是,happens-before原则也不是没有任何限制,任何场景都能happens-before的,还是有一些规则要求的。
二、happends-before规则
1、程序顺序规则(Program Order Rule)
程序顺序规则(Program Order Rule):在单个线程内,按照程序代码的顺序,前一个操作 happens-before 后一个操作。
public class ProgramOrderExample {
    private int a = 0;
    private int b = 0;
    public void method() {
        a = 1;  // 操作1
        b = 2;  // 操作2,
        // 操作1 `happens-before` 操作2
    }
}
2、锁规则(Monitor Lock Rule)
锁规则(Monitor Lock Rule):对一个锁的解锁 happens-before 随后对这个锁的加锁。即在 synchronized 代码块或方法中,释放锁之前的所有操作对于下一个获取这个锁的线程是可见的。
public class MonitorLockExample {
    private int value = 0;
    private final Object lock = new Object();
    public void increment() {
        synchronized(lock) {
            value++;  // 操作在锁内
        }
    }
    public int getValue() {
        synchronized(lock) {
            return value;  
        }
    }
}
increment 方法中对 value 的修改,在 getValue 方法获取锁之后是可见的。
3、volatile 变量规则(Volatile Variable Rule)
volatile 变量规则(Volatile Variable Rule):对一个 volatile 字段的写操作 happens-before 任意后续对这个字段的读操作。即确保 volatile 变量的写操作对其他线程立即可见。
public class VolatileExample {
    private volatile boolean flag = false;
    public void writeFlag() {
        flag = true;  // volatile 写操作
    }
    public boolean checkFlag() {
        return flag;  
    }
}
当一个线程调用 writeFlag(),另一个线程随后调用 checkFlag() 将看到 flag 为 true
4、线程启动规则(Thread Start Rule)
线程启动规则(Thread Start Rule):对线程的 start() 方法的调用 happens-before 该线程的每个动作。确保线程启动时,主线程中对共享变量的写操作对于新线程是可见的
public class ThreadStartExample {
    private int startValue = 10;
    public void startNewThread() {
        startValue +=1;
        new Thread(() -> {
            int localValue = startValue; 
            // 处理 localValue
        }).start();
    }
}
线程启动时,将看到 startValue 的值为 11
5、线程终止规则(Thread Termination Rule)
线程终止规则(Thread Termination Rule):一个线程的所有操作 happens-before 对这个线程的 join() 方法的成功返回。确保线程终止时,该线程中的所有操作对于调用 join() 方法的线程是可见的
public class ThreadJoinExample {
    private int counter = 0;
    public void incrementInThread() throws InterruptedException {
        Thread thread = new Thread(() -> {
            counter++;
        });
        thread.start();
        thread.join();  // `happens-before` counter 的读操作
        int value = counter;  // 这里能够看到线程中对 counter 的修改
    }
}
主线程中可以看到子线程对counter的修改
6、线程中断规则(Thread Interruption Rule)
线程中断规则(Thread Interruption Rule): 对线程的 interrupt() 方法的调用 happens-before 被中断线程检测到中断事件的发生。即线程的中断操作在被该线程检测到之前已经发生
7、对象终结规则(Finalizer Rule)
对象终结规则(Finalizer Rule): 一个对象的初始化完成(构造函数执行结束)happens-before 它的 finalize() 方法的开始。即在对象被回收前,其构造过程已经完全结束
public class FinalizerExample {
    private int value;
    public FinalizerExample() {
        value = 10;  // 构造函数中的操作
    }
    @Override
    protected void finalize() {
        // 此方法 `happens-before` 构造函数中的操作
        if (value != 10) {
            // 这里不应该发生
        }
    }
}
8、传递性(Transitivity)
传递性(Transitivity):如果操作 A 先行发生于操作 B,操作 B 先行发生于操作 C,那就可以得出操作 A 先行发生于操作 C 的结论
public class TransitivityExample {
    private volatile boolean ready;
    private int number;
    public void writer() {
        number = 42;       // 操作 A
        ready = true;      // 操作 B
    }
    public void reader() {
        if (ready) {              // 操作 C(由于 ready 是 volatile,它 `happens-before` 这里的操作)
            assert number == 42;  // 因为 A `happens-before` B,B `happens-before` C,所以 A `happens-before` C
        }
    }
}
由于 ready 是一个 volatile 变量,写入 ready(操作 B)发生在读取 ready 之前,同样,写入 number(操作 A)发生在写入 ready 之前。根据传递性规则,写入 number 发生在读取 ready 之前
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号