Java并发编程 - Java内存模型(JMM)

简介: Java并发编程 - Java内存模型(JMM)

Java内存模型与硬件内存架构的关系

通过对前面的硬件内存架构、Java内存模型以及Java多线程的实现原理的了解,我们应该已经意识到,多线程的执行最终都会映射到硬件处理器上进行执行,但Java内存模型和硬件内存架构并不完全一致。对于硬件内存来说只有寄存器、缓存内存、主内存的概念,并没有工作内存(线程私有数据区域)和主内存(堆内存)之分,也就是说Java内存模型对内存的划分对硬件内存并没有任何影响,因为JMM只是一种抽象的概念,是一组规则,并不实际存在,不管是工作内存的数据还是主内存的数据,对于计算机硬件来说都会存储在计算机主内存中,当然也有可能存储到CPU缓存或者寄存器中,因此总体上来说,Java内存模型和计算机硬件内存架构是一个相互交叉的关系,是一种抽象概念划分与真实物理硬件的交叉。(注意对于Java内存区域划分也是同样的道理)。


image.pngimage.png

image.pngimage.pngimage.png




整个是个JVM,但是“线程-工作内存-主内存”属于JMM。

JVM将内存组织为主内存和工作内存两个部分。

主内存主要包括本地方法区和堆。每个线程都有一个工作内存,工作内存中主要包括两个部分,一个是属于该线程私有的栈和对主存部分变量拷贝的寄存器(包括程序计数器PC和CPU工作的高速缓存区)。

1、所有的变量都存储在主内存中(虚拟机内存的一部分),对于所有线程都是共享的。

2、每条线程都有自己的工作内存,工作内存中保存的是主存中某些变量的拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。

3、线程之间无法直接访问对方的工作内存中的变量,线程间变量的传递均需要通过主内存来完成。

JMM是一个规范,规范Java虚拟机与计算机内存是如何协同工作的,规定一个线程如何和何时能够看到其他线程修改过的共享变量的值以及在必须时如何同步地访问共享变量。 为了屏蔽硬件和操作系统的内层的访问差异,以实现让JAVA程序在各种平台上一致的并发效果,Java虚拟机规范中定义了“Java内存模型”。


Heap(堆):运行时的数据区,是由垃圾回收负责;


优势:可以动态分配内存大小,生存期也不必事先告诉编译器,运行时动态分配内存,垃圾回收器会在不需要使用这些内存时,回收掉;

缺点:因为时运行时动态分配内存,所以存储速度相对慢一些。

Stack(栈):栈内存储基本类型变量,列入:小写的int,char......


优势:存储速度比堆快,仅次于计算机的寄存器,栈的内存是可以共享的;

缺点:存在栈内的数据大小与生存期必须是确定的,缺乏灵活性。



image.png


每一个CPU都有一系列的寄存器 CPU在寄存器上执行的速度,远大于在主存上执行的速度。由于计算机的存储设备与处理器的预算速度之间,有几个数量级的差距,所以计算机系统不得不加入一层读写速度接近处理器运算速度的高级缓存,作为内存与处理器之间的缓冲,将运算需要的数据复制到缓存中,当运算结束后,再从缓存同步到内存中。

JAVA内存模型要求:调用栈和本地模型存放在栈,对象存放在堆上 对一个对象的引用(包含这个对象的变量、方法)是在栈上,这个对象本身是在堆上,一个对象的成员变量可能会随着对象自身存在堆上,不管这个变量是原始类型,还是引用类型,静态成员变量跟随类的定义一起存放在堆上;放在堆上的对象可以被所持有对这个对象引用的线程访问。当一个线程可以访问一个对象的时候,也可以访问这个对象的成员变量。如果两个线程同时访问一个对象的同一个方法,他们将会都访问成员变量,但是每一个线程都拥有这个成员变量的私有拷贝。



image.png


  • 当CPU需要读取主存内容时,可以把数据读到缓存中,然后读取到寄存器中执行操作,当CPU需要回显结果时候,会将内部寄存器的值刷新到缓存中,然后某个时间点回显到主存中。



image.png


线程和主内存之间抽象的关系:Java内存模型(JVM)只是对内存的物理划分,只局限在内存,而且是只局限在JVM的内存,线程间的通信必须经过主内存。

每个线程都有一个私有的本地内存,当线程A需要读取主内存共享变量时拷贝共享变量的副本,放到本地,主内存就是硬件内存是为了获取更好的运行速度,虚拟机和硬件系统可能会让工作内存优先存储于寄存器和高速缓存中。



image.png


image.pngimage.png

目录
相关文章
|
1天前
|
安全 Java 程序员
Java并发编程:理解并应用ReentrantLock
【4月更文挑战第30天】 在多线程的世界中,高效且安全地管理共享资源是至关重要的。本文深入探讨了Java中的一种强大同步工具——ReentrantLock。我们将从其设计原理出发,通过实例演示其在解决并发问题中的实际应用,以及如何比传统的synchronized关键字提供更灵活的锁定机制。文章还将讨论在使用ReentrantLock时可能遇到的一些挑战和最佳实践,帮助开发者避免常见陷阱,提高程序性能和稳定性。
|
1天前
|
缓存 Java 调度
Java并发编程:深入理解线程池
【4月更文挑战第30天】 在Java并发编程中,线程池是一种重要的工具,它可以帮助我们有效地管理线程,提高系统性能。本文将深入探讨Java线程池的工作原理,如何使用它,以及如何根据实际需求选择合适的线程池策略。
|
1天前
|
Java
Java并发编程:深入理解线程池
【4月更文挑战第30天】 本文将深入探讨Java中的线程池,解析其原理、使用场景以及如何合理地利用线程池提高程序性能。我们将从线程池的基本概念出发,介绍其内部工作机制,然后通过实例演示如何创建和使用线程池。最后,我们将讨论线程池的优缺点以及在实际应用中需要注意的问题。
|
1天前
|
Java 大数据 数据库连接
java编程的优点
【4月更文挑战第30天】java编程的优点
4 0
|
1天前
|
存储 安全 Java
【亮剑】Java并发编程中的四个关键字:ThreadLocal、Volatile、Synchronized和Atomic
【4月更文挑战第30天】Java并发编程涉及`ThreadLocal`、`Volatile`、`Synchronized`和`Atomic`四个关键机制。`ThreadLocal`为每个线程提供独立变量副本;`Volatile`确保变量可见性,但不保证原子性;`Synchronized`实现同步锁,保证单线程执行;`Atomic`类利用CAS实现无锁并发控制。理解其原理有助于编写高效线程安全代码。根据业务场景选择合适机制至关重要。
|
1天前
|
安全 Java API
Java 8新特性概述及其对编程实践的影响
【4月更文挑战第30天】本文将详细讨论Java 8的新特性,包括Lambda表达式、Stream API以及Optional类等,并探讨这些新特性如何改变了Java编程的实践。我们将通过实例代码展示这些新特性的用法,并分析其对提高代码可读性和编写效率的影响。
|
1天前
|
Java
Java并发编程:深入理解线程池
【4月更文挑战第30天】本文将深入探讨Java并发编程中的一个重要主题——线程池。我们将从线程池的基本概念入手,了解其工作原理和优势,然后详细介绍如何使用Java的Executor框架创建和管理线程池。最后,我们将讨论一些高级主题,如自定义线程工厂和拒绝策略。通过本文的学习,你将能够更好地理解和使用Java的线程池,提高你的并发编程能力。
|
1天前
|
存储 安全 Java
深入理解Java并发编程:线程安全与性能优化
【4月更文挑战第30天】在Java开发中,并发编程是一个复杂而又关键的领域。它允许多个线程同时执行,从而提高程序性能和资源利用率。然而,并发编程也带来了许多挑战,如数据不一致、死锁和线程安全问题。本文将深入探讨Java并发编程的核心概念,包括线程安全和性能优化策略。我们将通过实例分析如何在保证线程安全的同时提高程序性能,为Java开发者提供实用的指导。
|
1天前
|
Java 程序员 开发者
深入理解Java并发编程:线程同步与锁机制
【4月更文挑战第30天】 在多线程的世界中,确保数据的一致性和线程间的有效通信是至关重要的。本文将深入探讨Java并发编程中的核心概念——线程同步与锁机制。我们将从基本的synchronized关键字开始,逐步过渡到更复杂的ReentrantLock类,并探讨它们如何帮助我们在多线程环境中保持数据完整性和避免常见的并发问题。文章还将通过示例代码,展示这些同步工具在实际开发中的应用,帮助读者构建对Java并发编程深层次的理解。
|
1天前
|
存储 Java
深入理解Java虚拟机:JVM内存模型
【4月更文挑战第30天】本文将详细解析Java虚拟机(JVM)的内存模型,包括堆、栈、方法区等部分,并探讨它们在Java程序运行过程中的作用。通过对JVM内存模型的深入理解,可以帮助我们更好地编写高效的Java代码,避免内存溢出等问题。