并发编程之java内存模型
Posted wilsonsui
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发编程之java内存模型相关的知识,希望对你有一定的参考价值。
1、基本概念
- 程序:代码,完成某一任务,代码序列(静态的概念)
- 进程:程序在某些数据上的一次运行(动态概念)
- 线程:一个进程可能包含一个或多个线程(占有资源的独立单元)
2、JVM与线程
JVM虚拟机在类被调用的时候启动
先启动JVM线程---> 其他线程(main线程)
3、JVM内存区域
方法区
主要存放classloader加载的类信息、常量、静态变量、JIT即时编译的代码
实现信息共享
Class.forName 反射的操作区域
OOM内存溢出可能
java堆
存放大量的实例对象
A a = new A();
new A() 存放在堆区
实现信息共享
GC 工作区域
OOM内存溢出可能
VM stack 虚拟机栈
采用数据结构栈
java方法在运行时的内存模型
私有数据,只能该方法访问,无法进行数据共享
虚拟机栈存放满了 会导致内存溢出(递归调用就是方法不停进栈,没有出栈)
OOM内存溢出可能
程序计数器
存放java线程的私有数据,这个数据就是执行下一条指令的地址
本地方法栈
主要与native方法有关,本地方法
4、Java内存模型-JMM
JMM是一种规范,是一个抽象的概念。
主内存
存放的为共享的信息
工作内存(线程的自己的内存)
也是快内存区域,存放线程的私有信息
- 基本数据类型直接分配到工作空间
- 引用数据类型,引用的地址存放在工作内存,而引用的对象在堆(主存)中。
工作空间对应着JVM虚拟机模型中的虚拟机栈与程序计数器
工作方式
- 1、线程修改私有数据,直接在工作空间修改
- 2、线程修改共享数据,把数据复制到自己的工作空间中,然后在工作空间中进行修改,修改完成后,刷新主内存中的数据。
- 存在线程安全 下面解决线程安全问题
5、硬件内存架构与java内存模型
Cpu先到寄存器中找数据,没有再去高速缓存中找数据,没有最后在内存中找数据。
- 高速缓存分一级二级三级
- L1 读写最快,容量最小
- L2 次与L1,最常用
- L3 读写最慢,容量最大
CPU缓存存在数据不一致性问题
并发处理的数据不同步
解决方案
1、总线加锁(BUS) :把总线只提供一个CPU使用,其他CPU无法访问,降低CPU的吞吐量。
2、 缓存一致性协议: (MESI协议)
当cpu在缓存中操作数据时,如果该数据是共享变量,数据在缓存中读到寄存器中,进行修改并更新内存数据,并且把cache line缓存行置为无效,其他cpu发现cache line无效,则直接从内存中读数据
java线程与硬件处理器
单CPU情况下,采用的是时间分片算法。
多CPU情况如图上述,任务经过线程池,分配给线程处理,线程受OS内核的调度,进行执行,最终映射至硬件进行处理。
java内存模型与硬件内存架构的关系
交叉线为数据可能存在的位置
交叉会存在数据不一致
java内存模型的必要性
java内存模型的作用:规范内存数据和工作空间数据的交互
6、并发编程的三个重要特性
原子性
不可分隔,转账:要么同时成功,要么同时失败。
x=1 就是原子性,x++不具备原子性
可见性
线程只能操作自己工作空间中的数据,自己的工作空间数据不对其他线程可见。
有序性
程序中的代码执行顺序,不一定就是程序执行的顺序。
两种重排序
- 编译重排
- 指令重排
如果对结果的运行没有影响,cpu会发生重排序
提高程序效率。
7、JMM对三个特征的保证
jmm与原子性
-
x=10 写操作 原子性
- 如果是私有数据,具有原子性
- 如果是共享数据,不具有原子性,(需要先将内存中数据读取到工作空间中,这个过程不具有原子性)
-
y=x 无原子性
- 把数据X读到工作空间,在把X的值赋值给y(这是两步操作,不具有原子性)
-
i++ 无原子性
- i=i+1,读i值到工作空间中,给i自增1,重新写入内存中。(多个原子性的单操作合并一起,就不具备原子性 )
-
z=z+1 没有原子性
- 与i++一样
多个原子性操作,合并起来就不具备原子性
保证原子性的方式
- Synchronized
- juc Lock
jmm与可见性
- volatile
在jmm内存模型上实现MESI协议
volatile对修饰的代码不允许重排序
- synchronized
加锁 保证只能一个线程访问
- JUC lock
lock也是一种锁
jmm与有序性
as-if-serial原则
as-if-serial 语义的意思是:所有的操作均可以为了优化而被重排序,但是你必须要保证重排序后执行的结果不能被改变,编译器、runtime、处理器都必须遵守 as-if-serial 语义。注意,as-if-serial 只保证单线程环境,多线程环境下无效。
在单线程中,重排后不影响执行的结果.
happens-before 原则
-
多线程下程序在运行中发生了重排,不影响结果
-
后一次加锁,必须等前一个解锁
-
volatile 修饰的代码不能进行重排序
-
传递原则 a在b之前,b在c之前 可以的到a在c之前执行。
-
如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。
-
两个操作之间存在happens-before关系,并不意味着一定要按照happens-before原则制定的顺序来执行。如果重排序之后的执行结果与按照happens-before关系来执行的结果一致,那么这种重排序并不非法。
总结
- jvm内存区域和JMM的关系
- jmm与硬件的关系
- jmm与并发编程三个特征
以上是关于并发编程之java内存模型的主要内容,如果未能解决你的问题,请参考以下文章
转:Java并发编程之十六:深入Java内存模型——happen-before规则及其对DCL的分析(含代码)
转: Java并发编程之十七:深入Java内存模型—内存操作规则总结
音视频开发之旅(52) - Java并发编程 之内存模型与volatile
音视频开发之旅(52) - Java并发编程 之内存模型与volatile
JUC并发编程 共享模型之内存 -- Java 内存模型 & 原子性 & 可见性(可见性问题及解决 & 可见性 VS 原子性 & volatile(易变关键字))(代码