juc并发编程02——JMM模型(上)

简介: 我们在这篇文章中将介绍JMM模型,也就是java内存模型。注意,本文所提到的JMM模型与JVM内存模型属于不同层次的内容。JVM内存模型讲的是物理内存空间的分配,而JMM则强调对于JVM内存模型的抽象。

1.java内存模型

在计算机中,为了解决主内存的速度跟不上处理器速度的问题,我们给每个处理器添加一级或多级高速缓存(如下图)。但是,每个处理器上缓存的数据如何保证一致性呢?

为了实现缓存数据的一致性,我们计算机中使用了缓存一致性协议。java中也有类似的机制来实现多线程的数据模型。

java的内存模型规定如下:


所有的变量均存在主内存中(这里及后文的变量指所有可能出现竞争的变量:包括成员变量、静态变量,不包括局部变量)

每个线程都有自己的工作内存,线程对变量的操作必须在工作内存中完成。不同线程之间的工作内存相互隔离。

那么这个内存模型在jvm中究竟是如何实现的呢?


主内存:对应堆中的实例对象

工作内存:对应虚拟机栈,虚拟机可能会对这部分内存进行优化,将其放入寄存器或者高速缓存中。

看如下实例。

public class Demo4 {
private static int i = 0;
    public static void main(String[] args) throws InterruptedException {
        new Thread(()-> {
            for(int j = 0; j < 1000000; j++) {
                i++;
            }
            System.out.println("thread1 run pass");
        }).start();
        new Thread(()-> {
            for(int j = 0; j < 1000000; j++) {
                i++;
            }
            System.out.println("thread2 run pass");
        }).start();
        Thread.sleep(1000);
        System.out.println(i);
    }
}

运行结果如下:

thread1 run pass
thread2 run pass
1729677

为什么呢?如果您有jvm的基础,就应该知道,原来自增操作并不是原子操作。可能出现如下图的情况。后面我们将讲解如何解决这个问题。

2.重排序

在编译或者运行期间,有可能会对指令进行重排序。有以下可能:

  • java编译器根据对java语义的理解进行重排序。
  • 现代处理器可能会对机器指令自主进行重排序。

在单线程的环境下,指令重排序可以在不改变执行结果的前提下优化代码的执行效率。但是多线程下指令重排序可能会导致一些问题。

public class Demo5 {
    private static int a = 0;
    private static int b = 0;
    public static void main(String[] args) {
        new Thread(() -> {
            if(b == 1) {
                if(a == 0) {
                    System.out.println("A");
                }
                if(a == 1) {
                    System.out.println("B");
                }
            }
        }
        ).start();
        new Thread(
                () -> {
                    a = 1;
                    b = 1;
                }
        ).start();
    }

按朴素的理解,上面代码的输出只有可能是"B"或者没有输出。但是上面a,b的赋值可能被重排序

public class Demo5 {
    private static int a = 0;
    private static int b = 0;
    public static void main(String[] args) {
        new Thread(() -> {
            if(b == 1) {
                if(a == 0) {
                    System.out.println("A");
                }
                if(a == 1) {
                    System.out.println("B");
                }
            }
        }
        ).start();
        new Thread(
                () -> {
                    b = 1;
                    a = 1;
                }
        ).start();
    }

因此可能出现结果为"A"的情况。

目录
打赏
0
0
0
0
4
分享
相关文章
高并发编程之什么是 JUC
高并发编程之什么是 JUC
86 1
JUC 并发编程之JMM
Java内存模型是Java虚拟机(JVM)规范中定义的一组规则,用于屏蔽各种硬件和操作系统的内存访问差异,保证多线程情况下程序的正确执行。Java内存模型规定了线程之间如何交互以及线程和内存之间的关系。它主要解决的问题是可见性、原子性和有序性。
JUC并发编程(上)
JUC并发编程(上)
99 0
JUC并发编程(下)
JUC并发编程(下)
54 0
JUC第二讲:Java并发理论基础:Java内存模型(JMM)与线程
JUC第二讲:Java并发理论基础:Java内存模型(JMM)与线程
127 0
高并发编程-重新认识Java内存模型(JMM)
高并发编程-重新认识Java内存模型(JMM)
162 0