JMM

JVM规范了视图定义一种JMM来屏蔽各个硬件平台和OS的内存访问差异,属于语言级的内存模型,实现让Java程序在各平台下都能达到一致的内存访问效果,通过禁止特定类型的编译器重排序和处理器重排序,为程序员提供一致的内存可见性保证

JMM定义了什么东西?

JMM定义了程序中的变量访问规则(程序执行的次序),但是,为了更好的执行性能,JMM没有限制执行引擎使用缓存,也没有限制编译器对指令进行重排序,即,在JMM中,会存在缓存一致性问题和指令重排序问题

JMM规定所有的变量都在主存中,每个线程有自己的工作内存,线程对变量的所有操作都必须在工作内存中进行,而不能直接对主存进行操作,并且每个线程不能直接访问其他线程的工作内存。

一些概念

  • 数据依赖性

    两个操作访问同一个变量,且有一个操作为写,此时会发生数据依赖性(写后读,读后写,写后写)

  • 顺序一致性(as-if-serial)

    顺序一致性内存模型是一个理论参考模型,在设计的时候,处理器的内存模型和编程语言的内存模型都会以顺序一致性内存模型作为参照。

    顺序一致性内存模型要求:

    • 线程中所有操作按照程序的顺序进行
    • (不管程序是否同步)所有线程都只能看到一个单一的操作执行顺序

    不管怎么重排序,(单线程)程序的执行结果不能被改变

  • 总线仲裁

    总线机制会把所有处理器对内存的访问以串行化方式执行

3个特性

  • 原子性

    要么做要么不做,举个例子

    x = 10;     //语句1
    y = x;      //语句2
    x++;        //语句3
    x = x + 1;  //语句4
    

    只有语句1是原子性操作,其他三个都不是

    也就是说,简单的读取、赋值(而且必须是将数字赋值给某个变量,变量之间的互相赋值不是原子操作)才是原子操作,JMM仅保证了基本读取和赋值(除去对long、double的操作)是原子操作,如果要实现更大范围的原子性操作,可以通过锁机制

  • 可见性

    java提供volatile关键字保证可见性,普通共享变量不能保证可见性。

    通过synchronized或者Lock也可以保证可见性,因为只有一个线程执行同步代码,执行完后会刷新主存。

  • 有序性

    允许编译器和处理器对指令进行重排序,不影响单线程,但影响并发。

    java中,可以通过volatile保证一定的“有序性”(它能禁止指令重排序)。另外,通过synchronized和Lock也可以。

    另外,JMM也具有一些先天的“有序性”(不用任何手段),也就是happens-before原则。如果两个操作的执行次序无法从happens-before原则推导出来,则不能保证它们的有序性,虚拟机可以随意对它们进行重排。

JMM定义线程和主寸的抽象关系

线程的共享变量存在主存中,每个线程有一个私有的本地内存,本地内存存储了该线程以读/写共享变量的副本。

t2.png

如果线程A与线程B之间要通信的话,必须要经历下面2个步骤。

  1. 线程A把本地内存A中更新过的共享变量刷新到主内存中去
  2. 线程B到主内存中去读取线程A之前已更新过的共享变量

指令重排序

执行程序时,为了提高性能,编译器和处理器常常会对指令做重排序。重排序分3种类型。

  • 编译器优化的重排序

    编译器在不改变单线程程序语义的前提下,可以重排源代码的执行顺序。多数处理器都允许写-读重排序,即将主存的共享变量都先读了下来,这样导致如果不加其他措施将会使得内部对外部共享变量的修改不可见。

  • 指令级并行的重排序
    现代处理器采用了指令级并行技术(Instruction-LevelParallelism,ILP)来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。

  • 内存系统的重排序

    由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。

t3.png

1为编译器重排序,2和3为处理器重排序。重排序会涉及内存可见性问题

对于编译器,JMM的编译器重排序规则会禁止特定类型的编译器重排序(不是所有的编译器重排序都要禁止)。

对于处理器,JMM的处理器重排序规则会要求Java编译器在生成指令序列时,插入特定类型的内存屏障指令,通过内存屏障指令来禁止特定类型的处理器重排序。

t5.png

happens-before原则:

happens-before规则对应一个或多个编译器和处理器重排序规则。如果一个操作的执行结果对另一个操作可见,那么这两个操作必须要存在happens-before关系(两个操作可以是位于一个线程或不同线程)

  • 程序次序规则:线程内,按照代码顺序,书写在前面的操作先于后者

    也就是,指令重排序仅对不存在数据依赖性的指令进行重排序,保证程序在单线程中执行结果的正确性

  • 锁定规则:一个unLock操作线性发生于后面对同一个锁的lock操作(先释放锁才能加锁)

  • volatile变量规则:对一个变量的写操作先于读操作

  • 传递规则:若操作A先发生于B,B先发生于C,那么操作A先发生于C

  • 线程启动规则:Thread对象的start()先行发生于此线程的每一个动作

  • 线程中断规则:对线程interrupt()的调用先行发生于被中断线程的代码检测到中断事件的发生

  • 线程终结规则:线程中所有的操作都先行发生于线程的终止检测

  • 对象终结规则:一个对象的初始化完成先发生于他的finalize()的开始

未同步程序的执行特性

对于未同步的多线程程序,JVM提供最小的安全性:设置默认值(0,Null,false),因而JVM在分配对象申请空间之后,会先将空间进行清零。

未同步程序整体是无序的,和顺序一致模型有如下差异:

  1. 不保证单线程内的操作按照程序顺序执行
  2. 不保证所有线程看到一致的操作执行顺序
  3. 不保证对64位的long型和double型变量的写操作具有原子性(在JSR-133之前的就内存模型中,对64位的long型和double型变量的读/写操作可以被拆分成两个32位的读/写操作来执行,之后进允许把一个64位的long型和double型变量的写操作可以被拆分成两个32位的写操作来执行,任意读操作都必须具有原子性)

参考:

《java并发编程的艺术》
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容