深入学习Java内存模型(Java面试问题)

简介: 你好我是辰兮,很高兴与你分享近期学习总结,上一篇整理完Java虚拟机内存结构,为了对比学习,本篇是对Java内存模型的介绍,整理完收获颇多,分享出来,希望对你们理解学习有帮助。

Java内存结构参考Java虚拟机的内存结构


一、简述Java内存模型

Java内存模型(Java Memory Model,JMM)是java虚拟机规范定义的,用来屏蔽掉java程序在各种不同的硬件和操作系统对内存的访问的差异,这样就可以实现java程序在各种不同的平台上都能达到内存访问的一致性。在这里插入图片描述
可以避免像c++等直接使用物理硬件和操作系统的内存模型在不同操作系统和硬件平台下表现不同,比如有些c/c++程序可能在windows平台运行正常,而在linux平台却运行有问题。

ps:JVM中的堆啊、栈啊、方法区什么的,是Java虚拟机的内存结构。内存模型概念如上,千千万万不要再搞混淆了。


二、CPU和缓存一致性

计算机在执行程序的时候,每条指令都是在CPU中执行的,而执行的时候,又免不了要和数据打交道。而计算机上面的数据,是存放在主存当中的,也就是计算机的物理内存。

随着CPU技术的发展,CPU的执行速度越来越快。而由于内存的技术并没有太大的变化,所以从内存中读取和写入数据的过程和CPU的执行速度比起来差距就会越来越大,这就导致CPU每次操作内存都要耗费很多等待时间。

不能因为内存的读写速度慢,就不发展CPU(中央处理器)技术了吧。

人们想到了用缓存来解决这个问题,就是在CPU和内存之间增加高速缓存。缓存的概念大家都知道,就是保存一份数据拷贝。他的特点是速度快,内存小,并且昂贵。

在这里插入图片描述

当程序在运行过程中,会将运算需要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主存当中。


Java内存模型的引入

Java内存模型规定了①所有的变量都存储在主内存中②每条线程还有自己的工作内存,③线程的工作内存中保存了该线程中是用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。

不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需要自己的工作内存和主存之间进行数据同步进行。
在这里插入图片描述

JMM就作用于工作内存和主存之间数据同步过程。

他规定了如何做数据同步以及什么时候做数据同步。


注意主内存和工作内存与JVM内存结构中的Java堆、栈、方法区等并不是同一个层次的内存划分,无法直接类比。

小结JMM是一种规范,目的是解决由于多线程通过共享内存进行通信时,存在的本地内存数据不一致、编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题。目的是保证并发编程场景中的原子性、可见性和有序性。


三、Java内存模型的实现

了解Java多线程的朋友都知道,在Java中提供了一系列和并发处理相关的关键字,比如volatile、synchronized、final、concurren包等。其实这些就是Java内存模型封装了底层的实现后提供给程序员使用的一些关键字。

在开发多线程的代码的时候,我们可以直接使用synchronized等关键字来控制并发,从来就不需要关心底层的编译器优化、缓存一致性等问题。所以,Java内存模型,除了定义了一套规范,还提供了一系列原语,封装了底层实现后,供开发者直接使用。

重点要介绍的就是,我们前面提到,并发编程要解决原子性、有序性和一致性的问题,我们就再来看下,在Java中,分别使用什么方式来保证。


1、原子性

  • 在Java中,为了保证原子性,提供了两个高级的字节码指令monitorenter和monitorexit。在synchronized的实现原理文章中,介绍过,这两个字节码,在Java中对应的关键字就是synchronized。
  • 因此,在Java中可以使用synchronized来保证方法和代码块内的操作是原子性的。

2、可见性

  • Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值的这种依赖主内存作为传递媒介的方式来实现的。
  • Java中的volatile关键字提供了一个功能,那就是被其修饰的变量在被修改后可以立即同步到主内存,被其修饰的变量在每次是用之前都从主内存刷新。因此,可以使用volatile来保证多线程操作时变量的可见性。
  • 除了volatile,Java中的synchronized和final两个关键字也可以实现可见性。只不过实现方式不同,这里不再展开了。

3、有序性

  • 在Java中,可以使用synchronized和volatile来保证多线程之间操作的有序性。
  • 实现方式有所区别:volatile关键字会禁止指令重排synchronized关键字保证同一时刻只允许一条线程操作

简单的介绍完了Java并发编程中解决原子性、可见性以及有序性可以使用的关键字。大家发现好像synchronized关键字是万能的,他可以同时满足以上三种特性,这其实也是很多人滥用synchronized的原因。

但是synchronized是比较影响性能的,虽然编译器提供了很多锁优化技术,但是也不建议过度使用。


大家可以参考《深入理解Java虚拟机》

The best investment is to invest in yourself

目录
相关文章
|
6天前
|
负载均衡 NoSQL 算法
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
这篇文章是关于Java面试中Redis相关问题的笔记,包括Redis事务实现、集群方案、主从复制原理、CAP和BASE理论以及负载均衡算法和类型。
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
|
6天前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
6天前
|
存储 监控 安全
一天十道Java面试题----第三天(对线程安全的理解------>线程池中阻塞队列的作用)
这篇文章是Java面试第三天的笔记,讨论了线程安全、Thread与Runnable的区别、守护线程、ThreadLocal原理及内存泄漏问题、并发并行串行的概念、并发三大特性、线程池的使用原因和解释、线程池处理流程,以及线程池中阻塞队列的作用和设计考虑。
|
4天前
|
前端开发 Java 编译器
【前端学java】如何从前端视角快速学习Maven
【8月更文挑战第12天】如何从前端视角快速学习Maven
12 2
【前端学java】如何从前端视角快速学习Maven
|
6天前
|
存储 NoSQL Java
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
这篇文章是关于Java面试中的分布式架构问题的笔记,包括分布式架构下的Session共享方案、RPC和RMI的理解、分布式ID生成方案、分布式锁解决方案以及分布式事务解决方案。
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
|
6天前
|
存储 安全 Java
一天十道Java面试题----第二天(HashMap和hashTable的区别--------》sleep、wait、join)
这篇文章是关于Java面试的第二天笔记,涵盖了HashMap与HashTable的区别、ConcurrentHashMap的实现原理、IOC容器的实现方法、字节码的概念和作用、Java类加载器的类型、双亲委派模型、Java异常体系、GC如何判断对象可回收、线程的生命周期及状态,以及sleep、wait、join、yield的区别等十道面试题。
一天十道Java面试题----第二天(HashMap和hashTable的区别--------》sleep、wait、join)
|
5天前
|
存储 Java 开发者
Java 内存模型与垃圾回收机制的深度剖析
在Java的世界里,理解其内存模型和垃圾回收机制是提升编程效率的关键。本文将通过浅显易懂的语言,带你深入了解Java的内存分配原理和垃圾回收过程,让你对Java的性能调优有更深刻的认识。
|
6天前
|
SQL Java 数据库连接
一天五道Java面试题----第六天(1)
这篇文章是关于Java面试中常见的五个问题,包括MyBatis和Hibernate的对比、MyBatis中#{}和${}的区别、MyBatis插件的运行原理及开发流程、索引的基本原理以及MySQL聚簇索引和非聚簇索引的区别。
|
6天前
|
缓存 NoSQL Redis
一天五道Java面试题----第九天(简述MySQL中索引类型对数据库的性能的影响--------->缓存雪崩、缓存穿透、缓存击穿)
这篇文章是关于Java面试中可能会遇到的五个问题,包括MySQL索引类型及其对数据库性能的影响、Redis的RDB和AOF持久化机制、Redis的过期键删除策略、Redis的单线程模型为何高效,以及缓存雪崩、缓存穿透和缓存击穿的概念及其解决方案。
|
6天前
|
前端开发 Java 数据库连接
一天十道Java面试题----第五天(spring的事务传播机制------>mybatis的优缺点)
这篇文章总结了Java面试中的十个问题,包括Spring事务传播机制、Spring事务失效条件、Bean自动装配方式、Spring、Spring MVC和Spring Boot的区别、Spring MVC的工作流程和主要组件、Spring Boot的自动配置原理和Starter概念、嵌入式服务器的使用原因,以及MyBatis的优缺点。