Java内存模型学习笔记
Java内存模型(JMM):描述了java程序中各种变量(线程共享变量)的范根规则,以及在JVM中将变量存储到内存和从内存中读取出变量这样的底层细节。共享变量就是指一个线程中的变量在其他线程中也是可见的。
什么是内存模型?
在多核系统中,处理器一般有一层或者多层的缓存,这些的缓存通过加速数据访问(因为数据距离处理器更近)和降低共享内存在总线上的通讯(因为本地缓存能够满足许多内存操作)来提高CPU性能。缓存能够大大提升性能,但是它们也带来了许多挑战。例如,当两个CPU同时检查相同的内存地址时会发生什么?在什么样的条件下它们会看到相同的值?
在处理器层面上,内存模型定义了一个充要条件,“让当前的处理器可以看到其他处理器写入到内存的数据”以及“其他处理器可以看到当前处理器写入到内存的数据”。有些处理器有很强的内存模型(strong memory model),能够让所有的处理器在任何时候任何指定的内存地址上都可以看到完全相同的值。而另外一些处理器则有较弱的内存模型(weaker memory model),在这种处理器中,必须使用内存屏障(一种特殊的指令)来刷新本地处理器缓存并使本地处理器缓存无效,目的是为了让当前处理器能够看到其他处理器的写操作或者让其他处理器能看到当前处理器的写操作。这些内存屏障通常在lock(加锁)和unlock(解锁)操作的时候完成。内存屏障在高级语言中对程序员是不可见的。
在强内存模型下,有时候编写程序可能会更容易,因为减少了对内存屏障的依赖。但是即使在一些最强的内存模型下,内存屏障仍然是必须的。设置内存屏障往往与我们的直觉并不一致。近来处理器设计的趋势更倾向于弱的内存模型,因为弱内存模型削弱了缓存一致性,所以在多处理器平台和更大容量的内存下可以实现更好的可伸缩性
“一个线程的写操作对其他线程可见”这个问题是因为编译器对代码进行重排序导致的。例如,只要代码移动不会改变程序的语义,当编译器认为程序中移动一个写操作到后面会更有效的时候,编译器就会对代码进行移动。如果编译器推迟执行一个操作,其他线程可能在这个操作执行完之前都不会看到该操作的结果,这反映了缓存的影响。
此外,写入内存的操作能够被移动到程序里更前的时候。在这种情况下,其他的线程在程序中可能看到一个比它实际发生更早的写操作。所有的这些灵活性的设计是为了通过给编译器,运行时或硬件灵活性使其能在最佳顺序的情况下来执行操作。在内存模型的限定之内,我们能够获取到更高的性能。
看下面代码展示的一个简单例子:
ClassReordering { int x = 0, y = 0; public void writer() { x = 1; y = 2; } public void reader() { int r1 = y; int r2 = x; } }
让我们看在两个并发线程中执行这段代码,读取Y变量将会得到2这个值。因为这个写入比写到X变量更晚一些,程序员可能认为读取X变量将肯定会得到1。但是,写入操作可能被重排序过。如果重排序发生了,那么,就能发生对Y变量的写入操作,读取两个变量的操作紧随其后,而且写入到X这个操作能发生。程序的结果可能是r1变量的值是2,但是r2变量的值为0。
Java内存模型描述了在多线程代码中哪些行为是合法的,以及线程如何通过内存进行交互。它描述了“程序中的变量“ 和 ”从内存或者寄存器获取或存储它们的底层细节”之间的关系。Java内存模型通过使用各种各样的硬件和编译器的优化来正确实现以上事情。
Java包含了几个语言级别的关键字,包括:volatile, final以及synchronized,目的是为了帮助程序员向编译器描述一个程序的并发需求。Java内存模型定义了volatile和synchronized的行为,更重要的是保证了同步的java程序在所有的处理器架构下面都能正确的运行。
内存变量
在多个线程之间能够被共享的变量被称为共享变量。共享变量包括所有的实例变量,静态变量和数组元素。他们都被存放在堆内存中,Volatile只作用于共享变量。
共享变量可见性的实现:假设目前有两个线程:线程1和线程2。线程1的读取主内存的x=0到线程1的工作内存中,并执行将x=1操作;主内存会将x的最新值更新过来,即x=1;最后线程2的工作内存会将主内存的最新值更新过来。
共享内存可见性的实现方式:synchronized实现和volatile实现
1.synchronized实现:
①线程解锁前,必须把共享变量的最新值刷新到主内存中;
②线程加锁时,将清空工作内容中的共享变量的值,从而使用共享变量需要从主内从中重新读取最新的值(注意:加锁与解锁需要同一把锁)
也就是说,线程解锁前对共享变量的修改,在下次加载时对其他线程也可见。线程执行互斥代码的过程如下:
1️⃣获得互斥
Java内存模型学习笔记的更多相关文章
- java 内存模型 ——学习笔记
一.Java 内存模型 java内存模型把 Java 虚拟机内部划分为线程栈和堆 下面这张图演示了调用栈和本地变量存放在线程栈上,对象存放在堆上. ==>> 一个局部变量可能是 ...
- Java内存模型学习笔记(一)—— 基础
1.并发编程模型的分类 在并发编程中,我们需要处理两个关键的问题:1.线程间如何通信,2.线程间如何同步.通信是指线程之间以何种机制来交换信息,同步是指程序用于不同线程之间操作发生相对顺序的机制. 在 ...
- Java 内存模型学习笔记
1.Java类 public class Math { public static final Integer CONSTANT = 666; public int math(){ int a = 1 ...
- 《Java并发编程实战》第十六章 Java内存模型 读书笔记
Java内存模型是保障多线程安全的根基,这里不过认识型的理解总结并未深入研究. 一.什么是内存模型,为什么须要它 Java内存模型(Java Memory Model)并发相关的安全公布,同步策略的规 ...
- 深入理解java内存模型--读书笔记
深入理解java内存模型 java内存模型的抽象 java线程之间的通信由java内存模型(JMM)控制,JMM决定一个线程对共享变量的写入何时对另一个线程可见 从抽象的角度来看,JMM决定了线程和主 ...
- 2016021801 - Java内存区域学习笔记
根据<深入理解java虚拟机>学习归纳整理学习笔记 程序计数器 用途:当前线程的字节码文件的行号指示器.(当前机场负责控制飞机降落的空管员:当前线程表示当前机场, 所执行的字节码等同于被等 ...
- java内存模型学习
根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 虚拟机的内存模型分为两部分:一部分是线程共享的,包括 Java 堆和方法区:另一部分是线程私有的,包括虚拟 ...
- <<深入Java虚拟机>>-第二章-Java内存区域-学习笔记
Java运行时内存区域 Java虚拟机在运行Java程序的时候会将它所管理的内存区域划分为多个不同的区域.每个区域都有自己的用途,创建以及销毁的时间.有的随着虚拟机的启动而存在,有的则是依赖用户线程来 ...
- Java并发编程(1)-Java内存模型
本文主要是学习Java内存模型的笔记以及加上自己的一些案例分享,如有错误之处请指出. 一 Java内存模型的基础 1.并发编程模型的两个问题 在并发编程中,需要了解并会处理这两个关键问题: 1.1.线 ...
随机推荐
- Adas术语简称
V2X: DSRC:专用短程通信(DSRC)的公用频谱信道交换数据
- Linux 依据关键字查找正在运行的进程
ps aux |grep tm1s
- 微信小程序开发--富文本插件wxParse的使用
昨天一位网友问我小程序怎么解析富文本.他尝试过把html转出小程序的组件,但是还是不成功,我说可以把内容剥离出来.但是这两种方法都是不行了.后来找到了wxParse-微信小程序富文本解析组件. 特性 ...
- [git] 能在关键时刻救命的git指令
* 查看所有分支的所有操作记录(关键时刻能救命) git reflog
- python基础类型—列表
列表 列表是python中的基础数据类型之一,其他语言中也有类似于列表的数据类型,比如js中叫数组,他是以[]括起来,每个元素以逗号隔开,而且他里面可以存放各种数据类型比如: li = [‘alex’ ...
- 算法提高 新建Microsoft Word文档
算法提高 新建Microsoft Word文档 时间限制:1.0s 内存限制:256.0MB 问题描述 L正在出题,新建了一个word文档,想不好取什么名字,身旁一人惊问:“你出 ...
- common lisp的几个基本概念
S-表达式 quote nil 与 () cons car cdr 真假 predicate 谓词与 t 与 nil null 函数 与 not 函数 if then else and 与 or de ...
- dubbo控制器xml文件报错
在配置dubbo服务的过程中,经常会遇到虽然程序能够跑起来,但是配置文件一堆红叉,虽然不影响功能,但是确实很让人恶心. 报错信息如下: Multiple annotations found at th ...
- qt ShaderEffect上的ShaderToy
https://zhuanlan.zhihu.com/p/38942460 发现这个挺好玩,有空学习一下
- python练习题-day16
1.用map来处理字符串列表,把列表中所有人都变成sb,比方alex_sb name=["alex","wupeiqi","yuanhao" ...