Java并发编程(二):JAVA内存模型与同步规则
一、Java内存模型(JMM)
它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。一个线程如何和何时能看到其他线程共享变量的值,以及在必须时如何同步访问共享变量。
JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间),用于存储线程私有的数据,而Java内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问,但线程对变量的操作(读取赋值等)必须在工作内存中进行,首先要将变量从主内存拷贝的自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存,不能直接操作主内存中的变量,工作内存中存储着主内存中的变量副本拷贝(私有拷贝)。

二、Java内存区域
堆:运行时的数据区,由垃圾回收来负责的,优点是 可以动态分配内存大小,(生存区)也不用事先告诉编译器,因为它是在运行时动态分配内存的,垃圾收集器会自动回收不再使用的对象。缺点: 由于是运行时动态分配内存,存取速度相对就比较慢一些。
栈:存取速度比堆要快,仅次于计算机里的寄存器,栈里的数据是共享的,但是存在栈中的数据大小与生存区必须是确定的,缺乏一些灵活性。 栈中主要存放一些基本的数据类型变量,比如小写的int,short,long ,byte,调用栈,本地变量存放在栈上,一个本地变量也可以是引用,指向堆中对象。本地变量是存在线程栈上的,尽管这些方法所处的对象处于堆上,一个对象的成员变量可能会随着对象自身存放在堆上,不管这个成员变量是原始类型还是引用类型,本地变量是存在线程栈上的,尽管这些方法所处的对象处于堆上,静态成员变量跟随着类的定义一起存放在堆上,存放在这个堆上的对象可以被所持有对这个对象的引用线程访问,当一个线程能访问这个对象,那么也能访问这个对象的成员变量,如果两个线程同时调用同一个方法的同一个成员变量,但是每一个线程都拥有这个成员变量的私有拷贝。

三、硬件架构

多个CPU,有的CPU还有多核,同时运行多个线程。每个CPU上的线程是可以并行执行的,每个CPU都包含一系列的寄存器,它们是CPu内存的基础。访问速度远大于主存的速度。所以内存和CPU之间有高速缓存,可能还有多级缓存,主存是很大的。
四、JMM与硬件架构的模型

硬件内存架构没有区别线程,栈和堆。对于硬件来说,都分布在主内存里,可能部分堆,栈分布在CPU缓存中或寄存器中
线程间共享变量在主内存里,每个线程都有一个私有的本地内存,他是JAVA内存模型的抽象概念,并不是真实存在的,它涵盖了缓存,缓冲区,以及其他的硬件和编译器的优化,存的是一个副本。
比如线程A从主内存拿到1放到自己的本地内存A,执行+1,再把2写回主内存。两个线程间的不同步性。

五、Java内存模型的的同步8中操作

Java虚拟机内存模型中定义了8种关于主内存和工作内存的交互协议操作:
- lock:作用于主内存的变量,把一个变量标识为一条线程独占状态。
- unlock:作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量可以被其他线程锁定。
- read:作用于主内的变量,把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。
- load:作用于工作内存的变量,把read读取操作从主内存中得到的变量值放入工作内存的变量拷贝中。
- use:作用于工作内存的变量,把工作内存中一个变量的值传递给java虚拟机执行引擎,每当虚拟机遇到一个需要使用到变量值的字节码指令时将会执行该操作。
- assign:作用于工作内存变量,把一个从执行引擎接收到的变量的值赋值给工作变量,每当虚拟机遇到一个给变量赋值的字节码时将会执行该操作。
- store:作用于工作内存的变量,把工作内存中一个变量的值传送到主内存中,以便随后的write操作使用。
- write:作用于主内存的变量,把store操作从工作内存中得到的变量值放入主内存的变量中。
Java内存模型对上述8种操作有如下的约束:
- 把一个变量从主内存复制到工作内存中必须顺序执行read读入操作和load载入操作。把一个变量从工作内存同步回主内存中必须顺序执行store存储操作和write写入操作。 read和load操作之间、store和write操作之间可以插入其他指令,但是read和load操作、store和write操作必须要按顺序执行,即不允许read和load、store和write操作之一单独出现。
- 不允许一个线程丢弃它的最近的assign赋值操作,即工作内存变量值改变之后必须同步回主内存。只有发生过assign赋值操作的变量才需要从工作内存同步回主内存。
- 一个新变量只能在主内存中产生,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量,即一个变量在进行use和store操作之前,必须先执行过assgin和load操作。
- 一个变量在同一时刻只允许一条线程对其进行lock锁定操作,但是lock锁定可以被一条线程重复执行多次,多次执行lock之后,只有执行相同次数的unlock操作变量才会被解锁。
- 如果对一个变量执行lock锁定操作,将会清空工作内存中该变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值。
- 如果一个变量事先没有被lock锁定,则不允许对这个变量进行unlock解锁操作,也不允许对一个被别的线程锁定的变量进行unlock解锁。
- 一个变量进行unlock解锁操作之前,必须先把此变量同步回主内存中(执行store和write操作)。
当一个变量被声明为volatile之后,JMM对其做了特殊规则:
- volatile变量的操作必须严格按load->use顺序,前一个动作是load时才能执行use动作,后一个动作是use时才能执行load动作,即每次在工作内存中使用变量前必须先从主内存中刷新最新的值,以保证能看到其他线程对变量的最新修改。
- volatile变量的操作必须严格按assign->store顺序,前一个动作是assign时才能执行store动作,后一个动作是store时才能执行assign动作,即每次在工作内存为变量赋值之后必须将变量的值同步回主内存,以保证让其他线程能看到变量的最新修改。
- 若线程对volatile变量V的assign或者use操作先于对volatile变量W的assign或者use操作,则线程对volatile变量A的read/load或者store/write操作也必定先于对volatile变量B的read/load或者store/write操作。
Java并发编程(二):JAVA内存模型与同步规则的更多相关文章
- Java并发编程二三事
Java并发编程二三事 转自我的Github 近日重新翻了一下<Java Concurrency in Practice>故以此文记之. 我觉得Java的并发可以从下面三个点去理解: * ...
- Java并发编程:Java的四种线程池的使用,以及自定义线程工厂
目录 引言 四种线程池 newCachedThreadPool:可缓存的线程池 newFixedThreadPool:定长线程池 newSingleThreadExecutor:单线程线程池 newS ...
- Java并发编程(1)-Java内存模型
本文主要是学习Java内存模型的笔记以及加上自己的一些案例分享,如有错误之处请指出. 一 Java内存模型的基础 1.并发编程模型的两个问题 在并发编程中,需要了解并会处理这两个关键问题: 1.1.线 ...
- 【Java并发编程二】同步容器和并发容器
一.同步容器 在Java中,同步容器包括两个部分,一个是vector和HashTable,查看vector.HashTable的实现代码,可以看到这些容器实现线程安全的方式就是将它们的状态封装起来,并 ...
- Java 并发编程(二):如何保证共享变量的原子性?
线程安全性是我们在进行 Java 并发编程的时候必须要先考虑清楚的一个问题.这个类在单线程环境下是没有问题的,那么我们就能确保它在多线程并发的情况下表现出正确的行为吗? 我这个人,在没有副业之前,一心 ...
- Java并发编程原理与实战三十三:同步容器与并发容器
1.什么叫容器? ----->数组,对象,集合等等都是容器. 2.什么叫同步容器? ----->Vector,ArrayList,HashMap等等. 3.在多线程环境下,为什么不 ...
- Java并发编程:Java内存模型JMM
简介 Java内存模型英文叫做(Java Memory Model),简称为JMM.Java虚拟机规范试图定义一种Java内存模型来屏蔽掉各种硬件和系统的内存访问差异,实现平台无关性. CPU和缓存一 ...
- Java并发编程 (二) 并发基础
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一.CPU多级缓存-缓存一致性 1.CPU多级缓存 上图展示的是CPU高级缓存的配置,数据的读取和存 ...
- 【Java并发编程二】Java并发包
1.Java容器 1.1.同步容器 Vector ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问.数组的缺点是每个元素之间不能有间隔,当数组大小不满足时 ...
随机推荐
- zk选举过程
1. 服务器启动时期的Leader选举 若进行Leader选举,则至少需要两台机器,这里选取3台机器组成的服务器集群为例.在集群初始化阶段,当有一台服务器Server1启动时,其单独无法进行和完成Le ...
- Apache的Order Allow,Deny详解
Allow和Deny可以用于apache的conf文件或者.htaccess文件中(配合Directory, Location, Files等),用来控制目录和文件的访问授权. 所以,最常用的是: O ...
- 流畅的python第五章一等函数学习记录
在python中,函数是一等对象,一等对象是满足以下条件的程序实体 1在运行时创建 2能复制给变量或数据结构的元素 3能作为参数传给函数 4能作为函数的返回结果 高阶函数(接受函数作为参数或者把函数作 ...
- TensorFlow进阶(一)----张量的阶和数据类型
张量的阶和数据类型 TensorFlow用张量这种数据结构来表示所有的数据.你可以把一个张量想象成一个n维的数组或列表.一个张量有一个静态类型和动态类型的维数.张量可以在图中的节点之间流通.其实张量更 ...
- Microsoft.VisualStudio.Shell.14.0.dll 文件位置
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Platform\Shel ...
- tornado 多进程模式
https://www.douban.com/note/217901726/ 官方文档的helloworld实例中的启动方法: if __name__ == "__main__": ...
- IOS 开发学习33 使用sqlite3
sqlite3 命令行简单使用 sqlite3 路径 //打开数据库路径连接 select * from sqlite_master where type="table"; //显 ...
- 关于app更新安装闪退和EditText长按出现的水滴颜色设置问题
关于app应用内更新安装后闪退的问题,解决办法如下: private void updateApp(File body) { Intent intent = new Intent(Intent.ACT ...
- TP框架模板中默认值输出
TP框架模板中默认值输出 我们可以给变量输出提供默认值,例如: {$user.nickname|default="这家伙很懒,什么也没留下"} 对系统变量依然可以支持默认值输出,例 ...
- ASP.Net MVC3/4中Model验证错误信息的本地化
最近使用ASP.Net MVC4做一个B/S的管理系统,里面有N多的Action和View Model,View Model上又有N多的验证. 一开始写的时候虽然知道要实现多语言,但是没有过多考虑,本 ...