有哪些网站可以用,用凡科做网站有自己的域名,时光慢网站建设方案论文,网站推广方案200字JMM(Java内存模型)
概述 JMM即Java内存模型(Java Memory Model),是一种抽象的概念,并不真实存在,JMM描述的是一组规则或规范,通过这组规范定义了程序中各个变量的访问方式Java内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问,但线程对变量的操…JMM(Java内存模型)
概述 JMM即Java内存模型(Java Memory Model),是一种抽象的概念,并不真实存在,JMM描述的是一组规则或规范,通过这组规范定义了程序中各个变量的访问方式Java内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问,但线程对变量的操作必须在工作内存中进行,所以首先要将变量从主内存拷贝的自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存,不能直接操作主内存中的变量JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存,用于存储线程私有的数据工作内存中存储着主内存中的变量副本拷贝,不同的线程间无法访问对方的工作内存,线程间的通信必须通过主内存来完成
JMM规范 JMM与JVM内存区域都存在共享数据区和私有数据区的概念
在JMM中主内存属于共享数据区从某个程度上讲应该包括了堆和方法区在JMM中工作内存属于线程私有数据区从某个程度上讲则应该包括程序计数器、虚拟机栈以及本地方法栈
JMM与硬件内存架构的关系 从上图可以得出JMM和计算机硬件内存架构是一个相互交叉的关系是一种抽象概念划分与真实物理硬件的交叉。最终多线程的执行最终都会映射到硬件处理器上进行执行,Java内存模型和硬件内存架构并不完全一致JMM对内存的划分对硬件内存并没有任何影响,不管是工作内存的数据还是主内存的数据对于计算机硬件来说在计算机主内存、CPU缓存或者寄存器中都可能存在
硬件内存分为寄存器、CPU缓存、主内存JMM分为工作内存线程私有数据区域和主内存堆内存
JMM作用
多个线程同时对一个主内存中的实例对象的变量进行操作有可能导致线程安全问题,所以需要JMM保证主内存与工作内存间数据一致 从上图可以得出如下信息
CPU的运行并不是直接操作内存而是先把内存里边的数据读到缓存而内存的读和写操作在并发场景下就会造成不一致的问题。所以JVM规范中定义一种Java内存模型(java Memory Model简称JMM)来屏蔽掉各种硬件和操作系统的内存访问差异以实现让Java程序在各种平台下都能达到一致的内存访问效果;JMM规范了Java虚拟机与计算机内存是如何协同工作的规定了一个线程如何和何时可以看到由其他线程修改过后的共享变量的值以及在必要时如何同步的访问共享变量实现了线程和主内存之间的抽象关系
JMM内存交互操作 八种内存交互操作 JMM内存交互协议指的是主内存与工作内存之间的交互协议JMM定义了八种内存交互操作来定义一个变量应该如何从主内存拷贝到工作内存、如何从工作内存同步到主内存。 主内存和工作内存同步过程 主内存和工作内存同步变量值规则分析
不允许一个线程无原因地没有发生过任何assign操作把数据从工作内存同步回主内存中一个新的变量只能在主内存中诞生不允许在工作内存中直接使用一个未被初始化load或者assign的变量。即就是对一个变量实施use和store操作之前必须先自行assign和load操作。一个变量在同一时刻只允许一条线程对其进行lock操作但lock操作可以被同一线程重复执行多次多次执行lock后只有执行相同次数的unlock操作变量才会被解锁。lock和unlock必须成对出现。如果对一个变量执行lock操作将会清空工作内存中此变量的值在执行引擎使用这个变量之前需要重新执行load或assign操作初始化变量的值。如果一个变量事先没有被lock操作锁定则不允许对它执行unlock操作也不允许去unlock一个被其他线程锁定的变量。对一个变量执行unlock操作之前必须先把此变量同步到主内存中执行store和write操作
JMM如何解决可见性有序性原子性问题
在多线程场景下,由于多线程情况复杂,为了保证每个线程能看到正确的结果,所以必须要保证线程的可见性,有序性与原子性
可见性问题 volatile关键字保证可见性。当一个共享变量被volatile修饰时它会保证修改的值立即被其他的线程看到即修改的值立即更新到主存中当其他线程需要读取时它会去内存中读取新值synchronized和Lock也可以保证可见性因为它们可以保证任一时刻只有一个线程能访问共享资源并在其释放锁之前将修改的变量刷新到内存中有序性问题 volatile关键字可以保证“一定程度上的有序性”一定程度上禁止指令重排synchronized和Lock也可以保证“一定程度上的有序性”不过与volitile的效果不同synchronized和Lock保证每个时刻只有一个线程执行同步代码相当于是让线程顺序执行同步代码自然就保证了有序性原子性问题 JDK提供的对基本数据类型读写操作的原子性,如AtomicInteger类等synchronized和Lock实现原子性。因为synchronized和Lock能够保证任一时刻只有一个线程访问该代码块 重排序
概述
重排序是编译器和处理器为了优化程序性能而对指令序列进行重排序,从Java源代码到最终实际执行的指令序列,会分别经历下面3种重排序 编译器重排序的典型就是通过调整指令顺序,在不改变程序语义的前提下,尽可能减少寄存器的读取、存储次数,降低了重复读取的开销,充分复用寄存器的存储值指令集并行的重排序是对CPU的性能优化,通过重排尽可能阻止流水线技术中断,提升CPU执行性能内存系统重排序可以通过伪重排序减少CPU与主内存交互时CPU的短暂卡顿,从而提升性能(但延时写入主内存可能会导致数据不一致)
数据依赖性
如果两个操作访问同一个变量且这两个操作中有一个为写操作此时这两个操作之间就存在数据依赖性,数据依赖性分为下列三种类型 上述三种情况下只要重排序两个操作的执行顺序程序的执行结果就会改变。编译器和处理器在重排序时会遵循数据依赖性编译器和处理器不会改变存在数据依赖性关系的两个操作的执行顺序
as-if-serial语义
不管怎么重排序(编译器为了提高并行度),(单线程)程序的执行结果不能被改变.编译器、runtime和处理器都必须遵守as-if-serial语义
重排序原则 内存屏障
内存屏障是为了禁止编译器重排序和CPU重排序,内存屏障在编译器和CPU层面上都有对应的指令(其中CPU的内存屏障是CPU提供的指令,可以由开发者显示调用) Happens-Before 规则
as-if-serial语义保证单线程内程序的执行结果不会被改变happens-before具有传递性关系保证正确同步的多线程程序的执行结果不会被改变。且两者的目的都是为了在不改变程序执行结果的前提下尽可能的提高程序执行的并行度程序顺序规则在一个线程内一段代码的执行结果是有序的在单线程情况下对不存在数据依赖性的指令进行重排序只保证单线程执行结果的正确性不保证程序在多线程中执行的正确性监视器锁规则就是无论是在单线程环境还是多线程环境对于同一个锁来说一个线程对这个锁解锁之后另一个线程获取了这个锁都能看到前一个线程的操作结果(管程是一种通用的同步原语synchronized就是管程的实现volatile变量规则就是如果一个线程先去写一个volatile变量然后一个线程去读这个变量那么这个写操作的结果一定对读的这个线程可见线程启动规则在主线程A执行过程中启动子线程B那么线程A在启动子线程B之前对共享变量的修改结果对线程B可见线程终结规则在主线程A执行过程中子线程B终止那么线程B在终止之前对共享变量的修改结果在线程A中可见线程中断规则对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生对象终结规则一个对象的初始化完成先行发生于他的finalize()方法的开始finalize垃圾回收机器Garbage Collection,也叫GC传递性如果操作A先行发生于操作B而操作B又先行发生于操作C则可以得出操作A先行发生于操作C 各个层面需要实现保证并发安全