了解Java内存模型,看完这一篇就够了
前言(此文草稿是年前写的,但由于杂事甚多一直未完善好。清明假无事,便收收尾发布了)
年关将近,个人工作学习怠惰了不少。两年前刚做开发的时候,信心满满想看看一个人通过自己的努力,最终能达到一个什么样的高度。而近半年
深陷生活的泥淖中,却有点被压迫住的感觉。个人成长、家庭、父母、朋友、身边的人,无不或多或少的影响着我的心境。很多时候还是要多反思一些,
通过思考让自己重拾信心,继续打满鸡血的前行。中国当前的大环境纵然有波折,但总体是向上的,互联网行业也是出于深度改造各行各业的状态,而且
个人对计算机对编程很有热情,一息理想尚存,想要自己的人生有所不同。所以不管怎样,这条路还要好好的走下去。这个把月多学习吧,为节后的
机会最好准备。
正文
闲话少叙,下面开始正题。首先要明确内存模型指什么。书中的定义是:在特定的操作协议下,对特定内存和高速缓存进行读写访问的过程抽象。
可以知道,内存模型就是来规定如何对内存/缓存进行读写操作的。所以Java内存模型,就是用来定义程序对java内存的的访问规则。进一步说, java内存
模型就是定义程序中变量(静态变量、数组对象元素等,不包括局部变量、方法参数)的访问规则。
Java内存模型的规定:
1、所有变量存储在主内存中;
2、每个线程都有自己的工作内存,且对变量的操作都是在工作内存中进行;
3、不同线程之间无法直接访问彼此工作内存中的变量,要想访问只能通过主内存来传递。
java的线程、工作内存、主内存关系如下图所示:

具体变量从主内存到工作内存,以及从工作内存转回主内存的实现细节,由下面八个原子性的操作完成:
lock:作用于主内存变量,将该变量标识为一个线程独占的状态
unlock:作用于主内存变量,将独占状态释放
read:作用于主内存变量,将值拷贝到工作内存中
load:作用于工作内存中的变量,将值放到工作内存中的变量副本中
use:作用于工作内存中的变量,将值传给执行引擎
asign:作用于工作内存中的变量,将执行引擎中的值赋给工作内存中的变量
store:作用于工作内存中的变量,将值传给主内存
write:作用于主内存中的变量,将工作内存中返回的值放到主内存变量中
同时还对上述八个操作进行了一些细节的要求,比如read/load、store/write必须成对出现,未执行过lock的变量不能执行unlock操作等。
划重点,此处面试常遇到的问题就是对于volatile关键字的解读。
volatile关键字
此关键字修饰的变量具有两种效果:1、保证线程间的可见性;2、阻止指令重排序
对于1的实现,它保证load与use必须相邻调用,即要use这个变量,必定先执行read/load,这样每次都能获取到最新的变量值;它又保证asign与store
必须相邻调用,即在工作内存中将该变量改了之后,必定会先同步到主内存中。这样,volatile关键字实现了可见性。至于阻止指令重排序,还是移步
《深入理解java虚拟机》一书吧,贫道水平有限,就不在这里说了。
从另一个角度来分析,Java内存模型是围绕着在并发过程中如何处理原子性、可见性、有序性来建立的。
原子性:八个原子性操作,以及synchronized(lock/unlock未直接开放给用户,synchronized通过monitorenter跟monitorexit指令调用的lock/unlock操作)
可见性:volatile、synchronized、final这三个关键字均通过不同方式实现了可见性
有序性:volatile、synchronized 这两个关键字保证有序性,同时还有先行发生(happens-before)原则来保证隐含的默认有序性
下面说说happens-before先行发生原则,先行发生原则用通俗语言表述就是:如果操作A在操作B之前发生,那么A产生的影响B同样能观测到。那么问题来
了,先行发生原则都有哪些呢?同样有八条,如下:
程序次序规则:同一个线程中按照代码的顺序依次执行
管程锁定规则:对于同一个锁,unlock先行发生于后面的lock,即unlock了才会lock
volatile变量规则:对一个volatile变量的写操作先行发生于后面对该变量的读操作,即写完了才会读
线程启动规则:一个线程的start()方法先行发生于此线程的任何一个动作
线程终止规则:一个线程的所有动作先行发生于该线程的终止检测
线程中断规则:对一个线程interrupt()方法的调用先行发生于线程的中断检测Thread.interrpted()
对象终结规则:对象的初始化完成先行发生于finalize()方法
传递性:顾名思义,A先行发生于B,B先行发生于C,则A一定先行发生于C
总结
java内存模型基本就这些内容,如果都掌握了的话,非一线互联网公司基本都能应对自如了(因为一线互联网公司贫道本人也没进去><)。
了解Java内存模型,看完这一篇就够了的更多相关文章
- Springboot 整合RabbitMq ,用心看完这一篇就够了
该篇文章内容较多,包括有rabbitMq相关的一些简单理论介绍,provider消息推送实例,consumer消息消费实例,Direct.Topic.Fanout的使用,消息回调.手动确认等. (但是 ...
- 什么是服务端渲染、客户端渲染、SPA、预渲染,看完这一篇就够了
服务端渲染(SSR) 简述: 又称为后端渲染,服务器端在返回html之前,在html特定的区域特定的符号里用数据填充,再给客户端,客户端只负责解析HTML. 鼠标右击点击查看源码时,页 ...
- Python虚拟环境和包管理工具Pipenv的使用详解--看完这一篇就够了
前言 Python虚拟环境是一个虚拟化,从电脑独立开辟出来的环境.在这个虚拟环境中,我们可以pip安装各个项目不同的依赖包,从全局中隔离出来,利于管理. 传统的Python虚拟环境有virtualen ...
- 【JVM】JVM内存结构 VS Java内存模型 VS Java对象模型
原文:JVM内存结构 VS Java内存模型 VS Java对象模型 Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点.而且很多概念的名称看起来又那么相似,很多人会傻傻分不清 ...
- 【转】JVM内存结构 VS Java内存模型 VS Java对象模型
JVM内存结构 我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途. 其中有些区域随着虚拟机进程的启动而 ...
- 区分 JVM 内存结构、 Java 内存模型 以及 Java 对象模型 三个概念
本文由 简悦 SimpRead 转码, 原文地址 https://www.toutiao.com/i6732361325244056072/ 作者:Hollis 来源:公众号Hollis Java 作 ...
- Java内存模型、JVM内存结构和Java对象模型
JVM内存结构 我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途.其中有些区域随着虚拟机进程的启动而存 ...
- [转帖]JVM内存结构 VS Java内存模型 VS Java对象模型
JVM内存结构 VS Java内存模型 VS Java对象模型 https://www.hollischuang.com/archives/2509 Java作为一种面向对象的,跨平台语言,其对象.内 ...
- 别再问什么是Java内存模型了,看这里!
网上有很多关于Java内存模型的文章,在<深入理解Java虚拟机>和<Java并发编程的艺术>等书中也都有关于这个知识点的介绍.但是,很多人读完之后还是搞不清楚,甚至有的人说自 ...
随机推荐
- 接口约束的另一种方法:Class类的isAssignableFrom
Class类的isAssignableFrom是个不常用的方法,感觉这个方法的名字取得不是很好,所以有必要在此解析一下,以免在看源码时产生歧义,这个方法的签名如下: public native boo ...
- C++动态库的几点认识
1.动态库也有lib文件,称为导入库,一般大小只有几k: 2.动态库有静态调用和动态调用两种方式: 静态调用:使用.h和.lib文件 动态调用: 先LoadLibrary,再GetProcAddres ...
- 使用 mybatis plus 动态数据源
1.pom.xml 增加 <dependency> <groupId>com.baomidou</groupId> <artifactId>dynami ...
- mac上terminal_问题_1117
(1)安装Homebrew /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install ...
- Nginx访问控制模块
一.Nginx访问控制模块 Nginx默认安装的模块http_access_module,可以基于来源IP进行访问控制. 1.模块安装 nginx中内置ngx_http_access_module,除 ...
- @ResponseBody 返回乱码 的解决办法
1:最快的 最简单的办法是 在Ajax请求脸面指定头信息Accept属性,StringHttpMessageConverter默认iso-8859-1编码,但是会根据请求头信息指定的编码格式来转换 ...
- javascript中数组总结
数组是所有高级语言都会有的东西,数组是JS中使用最多的类型之一,所以掌握JS中数组的用法相当有帮助: 由于JS是一门弱类型的语言,所以数组里面可以放各种不同的数据类型,比如 var a = [1993 ...
- java 判断用户是PC端和还是APP端登陆
java 判断用户是PC端和还是APP端登陆 public void getRequestHeader(HttpServletRequest request){ // 从浏览器获取请求头信息 Stri ...
- apache与tomcat负载集群集成方法配置
apache与tomcat负载集群集成方法有3种jk.jk_proxy.http_proxy apache:httpd-2.2.17-win32-x86-no_ssl.msi tomcat:apach ...
- 背水一战 Windows 10 (113) - 锁屏: 将 Application 的 Badge 通知和 Tile 通知发送到锁屏, 将 secondary tile 的 Badge 通知和 Tile 通知发送到锁屏
[源码下载] 背水一战 Windows 10 (113) - 锁屏: 将 Application 的 Badge 通知和 Tile 通知发送到锁屏, 将 secondary tile 的 Badge ...