当前位置: 首页 > 图灵资讯 > java面试题> 金三银四精选java面试题-指令重排有限制吗?happens-before了解吗?

金三银四精选java面试题-指令重排有限制吗?happens-before了解吗?

来源:图灵教育
时间:2024-01-01 19:22:04
 

指令重排有限制吗?happens-before了解吗?

指令重排也是有一些限制的,有两个规则happens-before和as-if-serial来约束。

happens-before的定义

  • 如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。
  • 两个操作之间存在happens-before关系,并不意味着Java平台的具体实现必须要按照 happens-before关系指定的顺序来执行。只要没有改变程序的执行结果,编译器和处理器怎么优化都可以

happens-before的六大规则

  • 程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作。

/**
 * 顺序性规则
 * 顺序执行是针对代码逻辑而言的,在实际执行的时候发生指令重排序但是并没有改变源代码的逻辑。
 * @author 百里
 */
public class BaiLiHappenBeforeDemo {
    public static void main(string[] args) {
        double pi = 3.14; // A
        double r = 1.0; // B
        double area = pi * r * r; // C
        System.out.println(area);
    }
}
  • 监视器锁规则:一个unlock操作之前对某个锁的lock操作必须发生在该unlock操作之前

import java.util.concurrent.locks.ReentrantLock;

/**
 * 重排锁的话,会导致逻辑改变。
 * @author 百里
 */
public class BaiLiHappenBeforeLockDemo {
    public static void main(String[] args) {
        ReentrantLock reentrantLock = new ReentrantLock();
        reentrantLock.lock();
        // TODO 
        reentrantLock.unlock();
        
        reentrantLock.lock();
        // TODO
        reentrantLock.unlock();
    }
}
  • volatile变量规则:对一个volatile变量的写操作必须发生在该变量的读操作之前。
  • 传递性规则:如果A happens-before B,且B happens-before C,那么A happens-before C。

从图中,我们可以看到:

  • “x=42”Happens-Before 写变量“v=true”,这是规则1的内容;
  • 写变量“v=true”Happens-Before 读变量“v=true”,这是规则3的内容;
  • 再根据这个传递性规则,我们得到结果:“x=42”Happens-Before 读变量“v=true”;

这意味着什么呢?如果线程 B 读到了“v=true”,那么线程A设置的“x=42”对线程B是可见的。也就是说,线程B能看到“x == 42“。

/**
 * 传递性规则
 * @author 百里
 */
public class BaiLiHappenBeforeVolatileDemo {
    int x = 0;
    volatile boolean v = false;
    public void writer() {
        x = 42;
        v = true;
    }
    public void reader() {
        if (v == true) {
            System.out.println(x);
        }
    }
}
  • 线程启动规则:如果线程A执行操作ThreadB.start()(启动线程B),那么A线程的ThreadB.start()操作happens-before于线程B中的任意操作。

我们可以理解为:线程A启动线程B之后,线程B能够看到线程A在启动线程B之前的操作。

  • 线程结束规则:如果线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作 happens-before于 ThreadB.join()操作成功返回后的线程A操作。

Java语言里面,Happens-Before的语义本质上是一种可见性,A Happens-Before B 意味着A事件对B事件来说是可见的,并且无论A事件和B事件是否发生在同一个线程里。