JAVA内存模型(JMM)详解

JAVA内存模型(JMM)详解

什么是JMM

JMM 是 Java Memory Model 的缩写,即 Java 内存模型,是一种制定了共享内存系统中多线程访问规则的抽象规范。它规定了 JVM 中各个线程之间的共享变量存储在主内存中,每个线程都有自己的工作内存和虚拟机栈,变量值的更改仅在工作内存中进行,需要同步到主内存中才能被其他线程看到。

JMM 可以保证 Java 多线程程序在并发执行时的可见性(Visibility)、有序性(Ordering)和原子性(Atomicity)。

JMM 规定的内存模型

在 JMM 的规范中,分别定义了以下不同的内存区域:

  • 主内存:所有变量的存储位置,是所有线程共享的。
  • 工作内存:每个线程中会包含有一个工作内存,线程的操作即在工作内存中进行。
  • 指令集:CPU 中的指令。
  • CAS 操作:原子操作的一种,即比较并交换。

JMM 同时也规定了以下行为:

  • 线程间通信(Lock,volatile 变量,synchronized,AtomicInteger 等):保证可见性、有序性和原子性。
  • happens-before 关系:保证程序运行的顺序。
  • 内存屏障(Memory Barriers):强制工作内存和主内存之间的通信。

JMM 的实例

以下是两个使用 JMM 的实例:

示例1:内存可见性

下面是一个简单的多线程示例,其中线程 A 在运行时修改了共享变量 count 的值,而线程 B 需要使用这个 count 值。如果不使用 JMM,线程 B 很大概率无法读取到线程 A 修改后的值。

public class VisibilityDemo {
    private volatile static int count = 0;

    public static void main(String[] args) {
        new Thread(() -> {
            while (count == 0) {}
            System.out.println(Thread.currentThread().getName() + " exit");
        }).start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        count = 1;
        System.out.println(Thread.currentThread().getName() + " set count to 1");
    }
}

使用 volatile 关键字可以让程序使用 JMM 模型:

private volatile static int count = 0;

输出结果为:

Thread-0 exit
main set count to 1

结论:使用 volatile 可以防止写操作前后的指令重排,保障了内存可见性。

示例2:原子性

明显的例子是多线程下的计数器,如果不是原子性的自增会导致不准确的结果,甚至程序奔溃。使用 JMM 的 AtomicInteger 可以将其变得更安全。

public class AtomicDemo{
    static AtomicInteger ai = new AtomicInteger(1);

    public static void main(String[] args){
        new Thread(() ->{
            int i = ai.getAndSet(2);
            System.out.println("Thread1: ai = " + ai + ", i = " + i);
        }).start();

        new Thread(() ->{
            int i = ai.getAndIncrement();
            System.out.println("Thread2: ai = " + ai + ", i = " + i);
        }).start();
    }
}

输出结果:

Thread1: ai = 2, i = 1
Thread2: ai = 3, i = 2

结论:使用 AtomicInteger 可以保证一个自增操作的原子性。

结论

JMM 的核心思想是通过将共享变量存储在主内存中,为每个线程创建一个工作内存,严格限制对共享变量的访问,保证并发环境下多线程的安全性。JMM 的实现方式和规范可以保证多线程程序的可见性、有序性和原子性要求,是 Java 多线程程序实现的重要基础。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JAVA内存模型(JMM)详解 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • Spring Boot应用程序同时支持HTTP和HTTPS协议的实现方法

    下面是关于如何实现Spring Boot应用程序同时支持HTTP和HTTPS协议的完整攻略: 准备工作 在实现HTTPS协议之前,我们需要准备一个SSL证书,可以选择购买正式的SSL证书或者自己生成一个自签名的证书。 在这里,我们示范自签名证书的生成方法: 生成自签名证书 安装openssl工具 在Linux环境中,可以通过包管理器进行安装:比如Ubuntu…

    Java 2023年5月20日
    00
  • JDK15正式发布(新增功能预览)

    JDK15正式发布(新增功能预览)攻略 简介 JDK15是Java开发工具包的最新版本,在2020年9月15日正式发布。它引入了许多新的功能和改进,帮助Java开发人员更轻松、更高效地开发应用程序。本文将为您提供JDK15版本的新功能的详细说明和使用示例。 新增功能 1. 文本块 Java 15中引入了文本块,这允许您在代码中以更自然的方式编写多行字符串。文…

    Java 2023年5月19日
    00
  • 深入理解Java8双冒号::的使用

    下面是“深入理解Java8双冒号::的使用”的完整攻略: 什么是双冒号:: 双冒号是Java 8中新增的一种语法,用于引用类的方法、构造函数或实例方法。它的形式类似于Lambda表达式,但又不完全一样。 双冒号的语法形式如下: ClassName::methodName 其中, ClassName 是类的名称,methodName 是类中的方法名。这种语法形…

    Java 2023年5月26日
    00
  • Java代码读取properties配置文件

    读取properties配置文件 package com.easycrud.utils; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import java.util.Map; import java.util.Properties; i…

    Java 2023年5月2日
    00
  • 使用Java实现系统托盘功能的介绍(附源码以及截图)

    使用Java实现系统托盘功能的介绍(附源码以及截图) 什么是系统托盘功能 系统托盘功能是指将图标置于系统托盘中,以提供快速访问与系统交互的功能,Windows系统右下角的区域就是系统托盘。Java在Swing开发中提供了 TrayIcon 和 SystemTray 两个类来实现该功能。 实现原理 使用 Java 中的 TrayIcon 和 SystemTra…

    Java 2023年5月24日
    00
  • Log4j2 重大漏洞编译好的log4j-2.15.0.jar包下载(替换过程)

    针对“Log4j2 重大漏洞编译好的log4j-2.15.0.jar包下载(替换过程)”这个问题,我来给出完整的攻略。大致流程如下: 下载log4j-2.15.0.jar包 查找使用Log4j2进行日志记录的应用程序 停止应用程序 将原来的log4j-core jar包和log4j-api jar包替换成log4j-2.15.0.jar包 重新启动应用程序,…

    Java 2023年5月20日
    00
  • Android Studio 一键生成Json实体类教程

    下面是详细的“Android Studio 一键生成Json实体类教程”的攻略: 1. 前言 在进行Android开发中,我们经常需要将从后台接口获取到的Json数据转化为实体类进行处理。手动创建实体类费时费力,尤其是在Json数据结构较为复杂的情况下。幸好,现在Android Studio提供了一个非常实用的插件,可以通过一键快速生成Json对应的实体类,…

    Java 2023年5月26日
    00
  • java实现计算器加法小程序(图形化界面)

    Java实现计算器加法小程序(图形化界面) 本文将详细讲解如何使用Java语言实现一个基本的计算器加法小程序,并提供代码示例说明。以下是完整的攻略: 步骤一:创建项目 首先,我们需要创建一个Java项目,并将其命名为“calculator”。 步骤二:添加图形用户界面 我们将会使用Java Swing库来添加图形用户界面(GUI)。 我们可以通过创建一个JF…

    Java 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部