Java并发编程—JMM(Java内存模型)在并发中的原理与应用

本文深入探讨了Java内存模型(JMM),包括JVM内存结构、Java对象模型,重点解析了JMM的重排序、可见性、happens-Before原则以及volatile关键字的作用。通过实例分析了如何利用volatile保证并发安全,讨论了其与synchronized的异同,并提出了面试中可能遇到的相关问题。
摘要由CSDN通过智能技术生成

1. JVM内存结构、Java内存模型与Java对象模型 辨析

1.1 JVM内存结构

JVM 内存布局 与 运行时数据区

1.2 Java内存模型

  • Java内存模型则是和并发编程相关。后面会仔细说明

1.3 Java对象模型

  • Java对象模型是指Java对象在虚拟机中的表现形式。

image

  • Java对象模型是对象自身的存储结构
  • JVM会给类创建一个instanceKlass保存着方法区,用在JVM层表示这个Java类
  • 当我们在代码中使用new创建一个对象时,JVM会创建一个instanceOopDesc对象,这个对象包含了对象头和实例数据。

2. Java内存模型(JMM)解析

  • Java内存模型,(JMM,Java Memory Model)实际上是一组JVM的规范。以便可以统一利用这些规范,更方便得开发多线程程序

2.1 重排序

  1. 重排序案例
/**
 * 重排序示例
 * @author yiren
 */
public class OutOfOrderExecution {
    private static int x = 0, y = 0;
    private static int a = 0, b = 0;

    public static void main(String[] args) throws InterruptedException {
        Thread one = new Thread(() -> {
            a = 1;
            x = b;
        });

        Thread two = new Thread(() -> {
            b = 1;
            y = a;
        });

        one.start();
        two.start();
        one.join();
        two.join();

        System.out.println("x=" + x + ", y=" + y);
    }
}

  • 我们可以想到产生的几种情况:
    1. a=1; x=b; b=1; y=a -> 结果:x=0,y=1
    2. b=1; y=a; a=1; x=b -> 结果:x=1,y=0
    3. b=1; a=1; x=b; y=a -> 结果:x=1,y=1
  • 第三种情况比较难出现,我们改造一下代码
/**
 * 重排序示例
 *
 * @author yiren
 */
public class OutOfOrderExecution {
    private static int x = 0, y = 0;
    private static int a = 0, b = 0;

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

            Thread two = new Thread(() -> {
                try {
                    countDownLatch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                b = 1;
                y = a;
            });

            one.start();
            two.start();
            countDownLatch.countDown();
            one.join();
            two.join();
            System.out.println("i=" + i + ", x=" + x + ", y=" + y);
        }
    }
}

...
i=147267, x=0, y=1
i=147268, x=0, y=1
i=147269, x=0, y=1
i=147270, x=0, y=1
i=147271, x=1, y=1

Process finished with exit code 0

  • 另外还有不容易想到的情况:也就是重排序的情况!x=0 y=0 我们修改下代码,将main函数前面代码改成如下:
    public static void main(String[] args) throws InterruptedException {
        x = 1;
        for (int i = 0; x != 0 || y != 0; i++) {
            x = 0;
            ....
复制代码
...
i=557, x=1, y=0
i=558, x=0, y=1
i=559, x=1, y=0
i=560, x=1, y=0
i=561, x=0, y=0

Process finished with exit code 0
复制代码
  • 如上:结果我们发现出现了x=0,y=0,为什么会出现这种情况呢?
    • 也就是我们程序在执行的时候 b=1和y=a 、a=1和x=b重排序了,也就是交换了执行顺序。在面试中被问到并发知识的时候,大多都会被问到“请你说一下自己对于AQS原理的理解”。下面给大家一个示例供大家参加,面试不是背题,大家一定要假如自己的思想,即使加入不了自己的思想也要保证自己能够通俗的讲出来而不是背出来。在此我向大家推荐一个架构学习交流圈。交流学习伪鑫:1253431195(里面有大量的面试题及答案)里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值