JMM概念JMM(JavaMemoryModel,简称JMM)本身是一个抽象概念JMM(JavaMemoryModel,JavaMemoryModel,简称JMM)本身就是一个抽象概念,并不真正存在。它描述了一套规则或规范,通过这套规范来定义程序中各种变量(包括实例字段、静态字段以及构成数组对象的元素)的访问方式。它并不真正存在。它描述了一组规则或规范,通过这些规则或规范定义了程序中各种变量(包括实例字段、静态字段和构成数组对象的元素)的访问方法。JMM对同步的规定:1.线程解锁前,必须将共享变量的值刷新回主存2.线程锁定前,必须将主存的最新值读入自己的工作内存3、加锁和解锁是同一个Lock由于JVM运行程序的实体是一个线程,而每个线程创建的时候,JVM都会为它创建一个工作内存(有的地方叫做栈空间)。工作内存是每个线程的私有数据区,而在Java内存模型中规定所有的变量都存放在主内存中,而主内存是一个共享内存区域,所有线程都可以访问,但是线程对变量的操作(读取和赋值等)必须在工作内存中进行。首先,必须将变量从主存复制到线程自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写入主存。不能直接操作主存中的变量。每个线程中的工作内存存储主内存中变量的副本。因此,不同的线程不能互相访问对方的工作内存,线程之间的通信(值传递)必须通过主内存来完成。简要访问过程如下图所示:JMM的八个内存交互操作比较直观。我们先来看看。这张图:锁(lock):作用于主存中的变量,一个变量一次只能被一个线程锁定,即变量被标记为线程独占状态。读取(read):作用于主存变量,表示将一个变量值从主存传送到线程的工作内存,以供下一次加载操作使用。加载(load):作用于线程工作内存的变量,表示将读操作从主内存中读取的变量值放入工作内存的变量副本中(副本是相对于变量的主存储器)。use(使用):作用于线程工作内存中的变量,表示将工作内存中的一个变量值传递给执行引擎,每当虚拟机遇到需要使用的字节码指令时就会执行操作变量的值。Assign(赋值):作用于线程工作内存的变量,表示将执行引擎返回的值赋值给工作内存中的变量。只要虚拟机遇到为变量赋值的字节码指令,就会执行此操作。store(存储):作用于线程工作内存中的变量,将工作内存中变量的值传送到主存中,供下次写操作使用。写(write):作用于主存的变量,意思是把store操作从工作内存中得到的变量的值放到主存的变量中。unlock(解锁):作用于主存的变量,表示释放处于锁定状态的变量,释放后的变量可以被其他线程锁定。JMM还规定了以上八个操作必须按照以下规则进行:read和load操作之一,store和write不允许单独出现,即load必须在read操作之后进行,write必须在存储操作之后执行。即不允许从主存读一个变量而工作存不接受,或者从工作存回写而主存不接受。不允许线程丢弃其最近的分配操作,即在工作内存中更改变量后,必须将更改同步回主内存。如果没有从工作内存分配到主内存,线程不允许同步数据。一个新的变量必须在主内存中创建,工作内存不允许直接使用一个未初始化的变量。也就是说,在对变量执行use和store操作之前,必须先经过load和assign操作。一次只有一个线程可以锁定一个变量。但是锁操作可以被同一个线程执行多次。多次加锁后,unlock必须执行相同次数后才能解锁。如果对一个变量进行了锁操作,那么这个变量在所有工作内存中的值都会被清空。在执行引擎使用这个变量之前,它必须用加载或赋值操作重新初始化变量的值。如果变量未锁定,则无法解锁。您也不能解锁被另一个线程锁定的变量。在线程解锁变量之前,它必须首先将变量同步回主存。JMM的三大特性JMM的三大特性是:原子性、可见性、有序性。整个JMM其实就是围绕着这三个特性构建的,它也是Java并发编程的基础。原子性原子性是指一个操作是不可分割的,不可中断的,要么全部执行成功,要么全部执行失败。JMM只能保证原始数据类型变量的原子读写,long和double除外(long和double的非原子契约)。让我们看看下面的例子:intx=1;整数y=x;x++;以上三行代码只有第一行是原子操作,基本类型赋值操作必须是原子操作。第二行代码先读取x变量的值,然后赋值给y变量。进行了两次操作,不能保证原子性。第三行代码先读取x变量的值,然后加1,最后赋值给x变量。进行了三个操作,不能保证原子性。在并发环境中,为了保证原子性,Java提供了synchronized关键字。因此,同步修改代码块之间的操作是原子的。可见性可见性意味着所有线程都可以看到共享内存的最新状态。即当一个线程修改共享变量的值时,其他线程可以立即看到该变量的最新值。针对可见性问题,Java提供了volatile关键字来保证可见性。当一个共享变量被volatile关键字修改时,该变量修改后会立即刷新到主存,保证其他线程看到的值一定是最新的。除了volatile关键字外,final和synchronized也可以启用可见性。一旦被final关键字修饰的变量在构造函数中被初始化,如果没有对象逃逸(意味着该对象可以不经初始化就被其他线程使用),那么其他线程就可以看到被final修饰的变量。synchronized的原理是线程进入synchronized代码块后,线程会获取锁,清空本地内存,然后将共享变量的最新值从主存拷贝到本地内存,执行code,并将修改后的copy值刷入主存,最后线程执行unlock。Sequence顺序是指按照代码执行的先后顺序,程序执行的先后顺序。在Java中,可以通过volatile和synchronized关键字来保证多线程之间的操作顺序。volatile关键字是通过在主存中加入内存屏障来禁止指令重新排序,保证有序性。synchronized关键字的原理是一个变量一次只能被一个线程加锁,必须先解锁,其他线程才能再次加锁,这样被synchronized修饰的代码块在多个线程间串行执行。【编者推荐】适合Vue用户的React教程,你值得拥有。微信视频号“多空”之争苹果禁用云游戏服务引发众怒,被指扼杀竞争臭游戏信息,泄露没人要?5G网络二维码的利与弊:安全隐患【责任编辑:江华电话:(010)68476606】
