Java内存模型(JMM)-happens-before
Java内存模型(JMM)是一种规范,用于定义多线程程序中,线程如何与主内存、工作内存以及其他线程之间进行通信和交互。
其中,happens-before是JMM中的一个重要概念,指的是一个操作的执行结果对后续操作可见。具体来说,如果操作A happens-before操作B,则操作A的结果对于操作B来说是可见的,即操作B可以看到操作A的执行结果。
happens-before关系的几种情况:
- 程序顺序规则:同一个线程中,前一条语句的执行结果对后一条语句可见。
- volatile变量规则:对一个volatile变量的写操作 happens-before 于后续对该变量的读操作。
- 传递性:如果操作A happens-before操作B,操作B happens-before操作C,那么操作A happens-before操作C。
- 管程锁规则:一个unlock操作 happens-before后续对同一个monitor的lock操作。
- 线程的启动规则:Thread对象的start()方法调用 happens-before于该线程的任何操作。
- 线程的终止规则:线程的所有操作都 happens-before于其他线程检测到这个线程已经终止。
- 中断规则:对线程 interrupt()方法的调用 happens-before于被中断线程的代码检测到中断事件的发生。
通过happens-before关系的规定,Java内存模型确保了多线程程序的一致性和可预测性,使得程序员能够在多线程环境中正确地进行操作。
Java内存模型(JMM)-happens-before作用:
-
程序顺序规则:在一个线程中,按照代码书写的顺序,前面的操作happens-before后面的操作。这保证了在一个线程中的操作是按照顺序执行的。
-
volatile变量规则:对一个volatile变量的写操作happens-before后续对该变量的读操作。这确保了volatile变量的写操作对其他线程可见。
-
锁规则:解锁操作happens-before后续对同一锁的加锁操作。这保证了线程释放锁之前的所有操作对于后续线程获得锁后的操作是可见的。
-
传递性:如果操作A happens-before操作B,操作B happens-before操作C,那么操作A happens-before操作C。这允许了happens-before关系的传递性。
"happens-before"关系的作用是保证了多线程程序的可见性和有序性。它提供了一种可靠的方式来避免数据竞争和不确定性行为。在编写多线程程序时,了解和正确使用"happens-before"关系是非常重要的。
Java内存模型(JMM)-happens-before理论
Java内存模型(JMM)是一种规范,用于定义线程如何与主内存和其他线程之间进行通信的方式。它确保多线程程序的一致性和可预测性。
在JMM中,happens-before关系是一个重要的概念。它定义了一组规则,用于确定在多线程程序中,一个操作的结果是否对另一个操作可见。
happens-before关系有以下几个规则:
-
程序顺序规则(Program Order Rule):在同一个线程中,按照程序的顺序,前面的操作happens-before于后面的操作。
-
管程锁规则(Monitor Lock Rule):一个解锁操作happens-before于后续对同一个锁的加锁操作。
-
volatile变量规则(Volatile Variable Rule):一个volatile变量的写操作happens-before于后续对该变量的读操作。
-
线程启动规则(Thread Start Rule):调用Thread对象的start()方法happens-before于启动的线程执行run()方法。
-
线程终止规则(Thread Termination Rule):一个线程在其他线程调用它的join()方法成功返回或者线程的isAlive()方法返回false之后,该线程的所有操作都happens-before于这个线程的终止。
-
线程中断规则(Thread Interruption Rule):对线程调用interrupt()方法happens-before于被中断线程检测到中断事件的发生。
-
对象终结规则(Finalizer Rule):一个对象的构造函数完成先于finalize()方法的开始。
-
传递性规则(Transitivity):如果操作A happens-before操作B,操作B happens-before操作C,则操作A happens-before操作C。
Java内存模型(JMM)-happens-before实例
public class HappensBeforeExample {private static int x = 0;private static int y = 0;private static boolean flag = false;public static void main(String[] args) throws InterruptedException {Thread writer = new Thread(() -> {x = 1; // 1flag = true; // 2});Thread reader = new Thread(() -> {if (flag) { // 3y = x; // 4}});writer.start();reader.start();writer.join();reader.join();System.out.println("x = " + x + ", y = " + y);}
}
解释:
- 写操作
x = 1
happens-before 写操作flag = true
。这是因为这两个操作属于同一个线程,按照程序的顺序执行,而且后一个操作依赖于前一个操作的结果。因此,第一个操作的结果对于第二个操作是可见的。 - 写操作
flag = true
happens-before 读操作if (flag)
。这是因为这两个操作分别在不同的线程中执行,而写操作的结果在内存中可见之后,读操作才能读取到正确的结果。通过happens-before规则,写操作的结果对于读操作是可见的。 - 读操作
if (flag)
happens-before 写操作y = x
。这是因为这两个操作分别在不同的线程中执行,而读操作必须在写操作之后进行,以确保读取到正确的结果。因此,通过happens-before规则,读操作在写操作之后发生。
根据这些happens-before关系,可以推导出最终的输出结果。在这个示例中,正确的结果应该是x = 1, y = 1
。这是因为写操作x = 1
和flag = true
之间存在happens-before关系,写操作flag = true
和读操作if (flag)
之间存在happens-before关系,读操作if (flag)
和写操作y = x
之间存在happens-before关系。
总结
-
程序顺序规则(Program Order Rule):在单个线程中,按照程序的顺序执行的操作,前面的操作happens-before于后面的操作。
-
volatile变量规则(Volatile Variable Rule):对一个volatile变量的写操作,happens-before对该变量的后续读操作。换句话说,对volatile变量的写操作具有可见性。
-
传递性(Transitivity):如果操作A happens-before操作B,操作B happens-before操作C,则操作A happens-before操作C。
-
管程中锁的规则(Lock Rule):一个unlock操作happens-before后续对同一个锁的lock操作。
-
线程的start()规则(Thread Start Rule):对于线程A来说,如果线程A的start()方法先于线程B的任意操作执行,那么线程A中的所有操作happens-before线程B中的任意操作。
-
线程的join()规则(Thread Join Rule):线程A执行了线程B的join()操作,那么线程B中的任意操作happens-before线程A的后续操作。
-
线程的中断规则(Thread Interruption Rule):对线程A进行interrupt()调用,会使得对线程A的后续操作happens-before对于调用interrupt()方法的线程的任意操作。
-
对象finalize规则(Finalizer Rule):一个对象的finalize()方法的执行,happens-before 对象的后续任意操作。