MST

星途 面试题库

面试题:Java内存模型中happens - before关系的基础概念

请阐述Java内存模型中happens - before关系的定义,以及它对多线程编程的影响。并举一个简单的代码示例说明如何体现happens - before关系。
13.9万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

happens - before关系的定义

在Java内存模型中,happens - before关系定义了两个操作之间的偏序关系。如果操作A happens - before操作B,那么操作A的执行结果对操作B是可见的,并且操作A按顺序排在操作B之前。它并不意味着操作A必须在操作B物理时间上先执行,而是保证在可见性和顺序上有这样的关系。具体规则如下:

  1. 程序顺序规则:在一个线程内,按照程序代码顺序,前面的操作happens - before后续的操作。
  2. 管程锁定规则:一个unlock操作happens - before后面对同一个锁的lock操作。
  3. volatile变量规则:对一个volatile变量的写操作happens - before后面对这个变量的读操作。
  4. 线程启动规则:Thread对象的start()方法happens - before此线程的每一个动作。
  5. 线程终止规则:线程中的所有操作都happens - before对此线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。
  6. 线程中断规则:对线程interrupt()方法的调用happens - before被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到是否有中断发生。
  7. 对象终结规则:一个对象的初始化完成(构造函数执行结束)happens - before它的finalize()方法的开始。
  8. 传递性:如果A happens - before B,且B happens - before C,那么A happens - before C。

对多线程编程的影响

  1. 可见性保证:happens - before关系确保了在满足该关系的情况下,前一个操作的结果对后续操作是可见的。这避免了线程间数据不一致的问题,比如一个线程修改了共享变量,另一个线程能够及时看到修改后的结果。
  2. 顺序性保证:它为多线程程序中的操作建立了一种顺序关系,使得程序员可以基于这种关系来推理程序的执行逻辑,从而编写正确的多线程代码。如果没有happens - before关系的保证,多线程程序中的操作顺序和数据可见性将变得不可预测,容易出现并发错误,如竞态条件等。

代码示例

public class HappensBeforeExample {
    private static volatile int num = 0;
    private static boolean flag = false;

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            num = 1; // 操作1
            flag = true; // 操作2
        });

        Thread thread2 = new Thread(() -> {
            while (!flag); // 操作3
            System.out.println(num); // 操作4
        });

        thread1.start();
        thread2.start();
    }
}

在这个例子中,根据happens - before关系:

  1. 在线程1中,操作1(num = 1)happens - before操作2(flag = true),这是基于程序顺序规则。
  2. 对于线程2,操作3(while (!flag))读取flag,操作2对flag的写操作happens - before操作3对flag的读操作,这是基于volatile变量规则(flag是volatile修饰的)。
  3. 由于传递性,操作1(num = 1)happens - before操作4(System.out.println(num))。所以当线程2执行System.out.println(num)时,能看到线程1对num的赋值,即输出1。这体现了happens - before关系在多线程编程中的可见性和顺序性保证。