Java 内存模型(一)

Java 内存模型(一)

Java 内存模型的抽象

​ 在 java 中,所有实例域、静态域和数组元素存储在堆内存中,堆内存在线程之间共享。局部变量,方法定义参数和异常处理器参数不会在线程之间共享,它们不会有内存可见性问题,也不受内存模型的影响。

​ Java 线程之间的通信由 Java 内存模型控制,JMM 决定一个线程对共享变量的写入何时对另一个线程可见。从抽象的角度来看,JMM 定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读 / 写共享变量的副本。本地内存是 JMM 的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。Java 内存模型的抽象示意图如下:

重排序

利用下面代码观察重排序现象(可能看不到重排序现象,仅作介绍):

import java.util.concurrent.CountDownLatch;

public class ReorderTest {
    private static int x = 0, y = 0;
    private static int a = 0, b = 0;

    public static void main(String[] args) throws InterruptedException {
        int i = 0;
        for (;;) {
            i ++;
            x = 0;
            y = 0;
            a = 0;
            b = 0;
            CountDownLatch latch = new CountDownLatch(1);
            Thread one = new Thread(() -> {
                try {
                    latch.await();
                } catch (InterruptedException e) {
                }
                a = 1;
                x = b;
            });
            Thread other = new Thread(() -> {
                try {
                    latch.await();
                } catch (InterruptedException e) {
                }
                b = 1;
                y = a;
            });
            one.start();other.start();
            latch.countDown();
            one.join();other.join();

            String result = "第" + i + "次 (" + x + "," + y + ")";
            if(x == 0 && y == 0) {
                System.err.println(result);
                break;
            } else {
                System.out.println();
            }
        }
    }
}

几秒后就可以得到 x == 0 && y == 0 这个结果,仔细看看代码就会知道,如果不发生重排序的话,这个结果是不可能出现的。

重排序由以下几种机制引起:

  1. 编译器优化:对于没有数据依赖关系的操作,编译器在编译的过程中会进行一定程度的重排。编译器是可以将 a = 1 和 x = b 换一下顺序的,因为它们之间没有数据依赖关系,同理,线程 2 也一样,那就不难得到 x == y == 0 这种结果了。

  2. 指令重排序:CPU 优化行为,也是会对不存在数据依赖关系的指令进行一定程度的重排,比如 CPU 流水线上指令乱序执行。

  3. 内存系统重排序:内存系统没有重排序,但是由于有缓存的存在,使得程序整体上会表现出乱序的行为。正是因为三级缓存结构的原因,所以才有了这个问题。

posted @ 2021-10-06 23:09  起床睡觉  阅读(25)  评论(0编辑  收藏  举报