`

Java多线程内存模型

阅读更多

JMM的基本概念,主内存与工作内存的数据交互方式与规则。多线程中的原子性、可见性、有序性。指令重排。volatile关键字

 


JMM的基本概念

Java作为平台无关性语言,JLS(Java语言规范)定义了一个统一的内存管理模型JMM(Java Memory Model)。JMM规定了jvm内存分为主内存和工作内存 ,主内存存放程序中所有的类实例、静态数据等变量,是多个线程共享的,而工作内存存放的是该线程从主内存中拷贝过来的变量以及访问方法所取得的局部变量,是每个线程私有的其他线程不能访问。每个线程对变量的操作都是以先从主内存将其拷贝到工作内存再对其进行操作的方式进行,多个线程之间不能直接互相传递数据通信,只能通过共享变量来进行。


 
从上图来看,线程1与线程2之间如要通信的话,必须要经历下面2个步骤:

  1. 首先,线程1把本地工作内存中更新过的共享变量刷新到主内存中去。
  2. 然后,线程2到主内存中去读取线程1之前已更新过的共享变量。
    典型的高并发引起的问题就存在由于线程读取到的数据还没有从另外的线程刷新到主内存中而引起的数据不一致问题。


主内存与工作内存的数据交互

JLS一共定义了8种操作来完成主内存与线程工作内存的数据交互:

lock:把主内存变量标识为一条线程独占,此时不允许其他线程对此变量进行读写
unlock:解锁一个主内存变量
read:把一个主内存变量值读入到线程的工作内存
load:把read到变量值保存到线程工作内存中作为变量副本
use:线程执行期间,把工作内存中的变量值传给字节码执行引擎
assign:字节码执行引擎把运算结果传回工作内存,赋值给工作内存中的结果变量
store:把工作内存中的变量值传送到主内存
write:把store传送进来的变量值写入主内存的变量中

使用标准的操作再来重现一下上方的2个线程之间的交互流程则是这样的:
线程1从主内存read一个值为0的变量x到工作内存
使用load把变量x保存到工作内存作为变量副本
将变量副本x使用use传递给字节码执行引擎进行x++操作
字节码执行引擎操作完毕后使用assign将结果赋值给变量副本
使用store把变量副本传送到主内存
使用write把store传送的数据写到主内存
线程2从主内存read到x,然后load–>use–>assign–>store–>write

另外使用这8种操作也有一些规则:
read 和 load必须以组合的方式出现,不允许一个变量从主内存读取了但工作内存不接受情况出现
store和write必须以组合的方式出现,不允许从工作内存发起了存储操作但主内存不接受的情况出现
工作内存的变量如果没有经过 assign 操作,不允许将此变量同步到主内存中
在 use 操作之前,必须经过 load 操作
在 store 操作之前,必须经过 assign 操作
unlock 操作只能作用于被 lock 操作锁定的变量
一个变量被执行了多少次 lock 操作就要执行多少次 unlock 才能解锁
一个变量只能在同一时刻被一条线程进行 lock 操作
执行 lock 操作后,工作内存的变量的值会被清空,需要重新执行 load 或 assign 操作初始化变量的值
对一个变量执行 unlock 操作之前,必须先把此变量同步回主内存中


多线程中的原子性、可见性、有序性

原子性:关于原子性的定义可以参考我的上篇博客《浅谈数据库事务》。在JLS中保证原子性的操作包括read、load、assign、use、store和write。基本数据类型(除了long 和double)操作都具有原子性。
如果需要更大范围的原子性操作的时候,可以使用lock和unlock操作来完成这种需求。
可见性:是指当一个线程修改了共享变量的值,其他线程是否能够立即得知这个修改。
由上方JMM的概念得知,线程操作数据是在工作内存的,当多个线程操作同一个数据的时候很容易读取到还没有被write到主内存变量的值。
Java是如何保证可见性的:volatile、synchronized、final关键字
有序性:在并发时,程序的执行可能会出现乱序。给人的直观感觉就是:写在前面的代码,会在后面执行。有序性问题的原因是因为程序在执行时,可能会进行指令重排,重排后的指令与原指令的顺序未必一致。关于指令重排会在下方讲。


指令重排

1
2
3
4
int a=1;
int b=2;
int c=3;
int d=4;

你能说出上方这段代码的执行顺序么?其实我们可能理所当然的以为它会从上往下顺序执行。事实上,在实际运行时,为了优化指令的执行顺序等,代码指令可能并不是严格按照代码语句顺序执行的。上方的代码执行顺序可能完全反过来,这个就是指令重排。
不过呢,指令重排也不是可以随意重排的,它需要遵守一定的规则:
程序顺序规则:一个线程内保证语义的正确性。
锁规则:解锁肯定先于随后的加锁前。
volatile规则:对一个volatile的写,先于volatile的读。
传递性:如果A 先于 B,且B 先于 C,那么A 肯定先于 C。
start()规则:线程的start()操作先于线程的其他操作。
join()规则:线程的所有操作先于线程的关闭。
程序中断规则:线程的中断先于被中断后执行的代码。
对象finalize规则:一个对象的初始化完成先于finalize()方法。


volatile关键字

volatile关键字旨在告诉虚拟机在这个地方要注意不能随意的进行指令重排,而虚拟机看到一个变量被volatile修饰以后就会采用一些特殊的手段来保证变量的可见性。不过要注意的是volatile关键字不能保证原子性。



 

  • 大小: 171.6 KB
  • 大小: 12.3 KB
0
0
分享到:
评论

相关推荐

    java内存模型和一些多线程的资料

    NULL 博文链接:https://zdsyouxiang.iteye.com/blog/939284

    27道顶尖的Java多线程、锁、内存模型面试题!.pdf

    27道顶尖的Java多线程、锁、内存模型面试题!.pdf

    Java内存模型和线程安全

    Java内存模型和线程安全,多线程开发,高并发处理,内存模型分析

    java内存模型(有助理解多线程)

    java内存模型,对初学者比较实用,理解后有助于多线程编程等

    java多线程详解,线程池原理,8种锁,java内存模型......

    首先希望大家喜欢我制作的文档,如果文档中有什么误解的地方,望告诉一下,5分是也不多,是系统默认的,那么就5分咯,java多线程详解,线程池原理,8种锁,java内存模型......

    一篇文章弄懂Java多线程基础和Java内存模型

    文章目录一、多线程的生命周期及五种基本状态二、Java多线程的创建及启动1.继承Thread类,重写该类的run()方法2.通过实现Runnable接口创建线程类3.通过Callable和Future接口创建线程三、Java内存模型概念四、内存间...

    java多线程设计模式详解(PDF及源码)

    去睡觉吧 第11章 Thread-Specific Storage——每个线程的保管箱 第12章 Active Object——接受异步消息的主动对象 总结 多线程程序设计的模式语言 附录A 练习问题的解答 附录B Java的内存模型 附录C Java线程的...

    27道顶尖的Java多线程、锁、内存模型面试题!.zip

    27道顶尖的Java多线程、锁、内存模型面试题!

    Java线程/内存模型的缺陷和增强

    它提供了Thread/Runnable/ThreadGroup等一系列封装的类和接口,让程序员可以高效的开发Java多线程应用。为了实现同步,Java提供了synchronize关键字以及object的wait()/notify()机制,可是在简单易用的背后,应藏着...

    深入理解java内存模型

    Java内存模型的抽象 重排序 处理器重排序与内存屏障指令 happens-before 重排序 数据依赖性 as-if-serial 语义 程序顺序规则 重排序对多线程的影响 顺序一致性 数据竞争与顺序一致性保证 顺序一致性内存模型 同步...

    深入理解Java内存模型.程晓明(带书签文字版).pdf

    Java 内存模型的抽象 4 重排序 6 处理器重排序与内存屏障指令 7 happens-before 10 重排序 13 数据依赖性 13 as-if-serial 语义 13 程序顺序规则 15 重排序对多线程的影响 15 顺序一致性 19 数据竞争与顺序...

    Java线程安全问题_动力节点Java学院整理

    其实java的多线程并发问题最终都会反映在java的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型,要解决两个主要的问题:可见性和有序性。我们都知道计算机有高速缓存...

    java会话管理、多线程.docx

    java多线程的创建,主流的几种创建方式都有详细的讲解。线程的交互以及线程的同步锁的问题都有具体的实例。java的内存模型,java会话都有讲解,如果是刚接触java多线程,可以下载来看看

    java并发之内存模型.docx

    Java的并发采用的是共享内存模型,Java线程之间的通信总是隐式进行,整个通信过程对程序员完全透明。如果编写多线程程序的Java程序员不理解隐式进行的线程之间通信的工作机制,很可能会遇到各种奇怪的内存可见性问题...

    Java同步线程模型分析与改进

    该文针对Java同步线程模型的缺陷,扩展synchronised关键字语法,使它支持多个参数和能接受一个超时说明;重新 定义wait()使它返回一个boolean变量来解决超时检测问题;通过扩展语法方法解决了同步问题,以确保使用...

    图解java多线程设计模式

    java.util.concurrent包、synchronized关键字、Swing框架、Java内存模型等内容也均有涉及,不仅能够了解Java多线程的相关知识,还可加深对Java语言的理解。 本书适合以下读者阅读 a.对多线程感兴趣的人 b.对Java...

    java内存模型介绍

    从JVM的角度介绍java的内存模型,包含多线程的内存分配情况

    深入理解Java内存模型

    java 内存 多线程 并发 锁。深入理解Java的内存模型,线程的同步,可以编写高效的多线程代码!

Global site tag (gtag.js) - Google Analytics