【JVM】JMM内存模型与volatile

JMM的出现,是为了屏蔽各种硬件和操作系统的内存访问差异,以实现让java程序在各种平台下都能达到一致的内存访问效果。

JMM主要的目标是定义程序中各个变量的访问规则。此处的变量仅考虑在共享区域的变量,共享的变量才有并发的意义,如实例字段,静态字段,够成数组的对象等。而不考虑局部变量,方法参数等线程私有的变量。

物理内存模型

我们可以通过物理的内存模型类比java内存模型。在物理计算机中,处理器需要经常与内存进行I/O操作,而计算机存储设备的速度与CPU运算速度有几个数量级的差距,为缓解这种差距带来的性能浪费,通常会在他们之前引入一个高速缓存设备【1】作为缓冲:将运算所需要的数据复制到缓冲中,让运算能快速执行,当运算结果结束后再从缓冲同步回内存之中。而这样一个环节速度矛盾的方法也会带来一个新问题:缓存一致性【2】。为此,也为处理器引入了一些协议来解决这一问题。除了高速缓存,为提高运算单元的利用率,处理器可能会对输入的代码进行乱序执行优化【3】

Java内存模型

通过物理内存模型,可以一一对应出java内存模型。【1】引入工作内存与主内存的概念,所有变量都存储在主内存中,每条线程有自己的工作内存,工作内存中保存了线程需要使用到的变量的主内存副本拷贝,线程对变量的操作都必须在工作内存中执行,不同线程之间也无法直接访问对方工作内存中的变量,变量传递需要借助主内存。【2】对于数据一致性问题,JMM也设定了主内存与工作内存中的交互协议。【3】JMM中也存在编译器的指令重排序进行优化,但这一问题也会对并发下的数据一致性产生影响,我们也设定了Happens-before规则保证最基本的代码执行结果正确,若要保证并发下的数据一致性,仍然是需要一些额外措施。


JMM数据一致性:原子性+可见性+有序性

可以看出,设计JMM需要解决的问题是数据一致性问题,在串行下这不算问题,但在并发下就会出现数据不一致。JMM中,只要保证了原子性、可见性和有序性,就能保证并发下的数据一致性。下面,我们分别分析这三点:

A、原子性

    java中,对基本数据类型的操作都是原子性。(long和double具有非原子协定:允许虚拟机将没有被volatile修饰的64位数据的读写操作划分为2次32位操作进行)

    具有原子性:synchronized、lock、CAS。前两者是通过锁的功能--在一个时刻只能有一个线程访问来保证的,后者CAS是计算机硬件操作,是通过硬件集成保证的。

B、可见性

1.  首先,java为数据一致性设定了主内存与工作内存之间的交互协议。8个基本操作以及与之对应的8个规则。

    锁相关:lock、unlock

    主内存-->工作内存-->执行引擎:read、load、use     (从主内存read进工作内存,load进工作内存的变量副本,在工作内存中使用(给执行引擎))

    执行引擎-->工作内存-->主内存:assign、store、write   (从执行引擎assign给工作内存中的变量,从工作内存中store进主内存中,在主内存中write进变量中)

8个规则(总结成四个):

    (1)必须按这个执行,不允许缺失或乱序 read-->load-->use 

    (2)assign-->store-->write  

    (3)一个变量的lock操作,在同一时间内只允许一个线程重复执行多次,并且只有执行相同次数的unlock该变量才能被释放 

    (4)释放锁unlock之前将最新数据写入主内存,进入锁lock之前将最新数据读入工作内存

2.  具有可见性:volatile 、sychronized、lock、final

    其中sychronized和lock具有可见性是因为规则4,而final修饰的是常量,不可变量,必然是可见的(在哪都一样)。

    volatile在后面讲解。

C、有序性

1.  happens-before(8个),JMM具有的先天有序性

    (1)程序次序规则:在一个线程内按顺序执行;

    (2)锁定规则:unlock先行发生于对同一个锁的lock;

    (3)volatile:对一个volatile的读规则先行发生于对其的写规则;

    (4)传递规则:a线性发生于b,b先于c,则a先于c;

    (5)线程启动规则:线程的start先行发生于其他所有操作;

    (6)线程中断:interrupt()(改变中断标志)先行发生于检测到中断事件的发生;

    (7)线程终止:线程其他所有动作先行发生于线程终结检测;

    (8)对象终结原则:对象初始化先行发生于finalize()。

2.具有有序性:volatile   lock、synchronize(同一时刻只允许一个线程访问+程序次序规则)

    volatile在后面讲解。


所以,通过上面的分析可知:lock sychronized是线程安全的,volatile只能保证可见性与有序性,不能保证线程安全。



Volatile

1.保证可见性和有序性

有序性:在编译的时候,编译器总是会进行优化,而volatile的意思是易变化的,就是告诉编译器,volatile修饰的变量随时会被意外修改,这个变量的值在当前上下文看来貌似没什么变化,但是有可能会被其他线程修改。

可见性:指的是看起来好像是直接对主内存进行操作一样,不管什么时候,其他线程看到的必然都是最新的值。

2.那么volatile是如何保证可见性与有序性的呢?

是通过内存屏障来保障的。

通过使用Lock前缀的指令禁止变量在线程工作内存中缓存来保证volatile变量的内存可见性、通过插入内存屏障禁止会影响变量内存可见性的指令重排序

3.为什么要使用Volatile & 适用场景?

Volatile变量修饰符如果使用恰当的话,它比synchronized的使用和执行成本会更低,因为它不会引起线程上下文的切换和调度。

In case only one thread reads and writes the value of a volatile variable and other threads only read the variable, then the reading threads are guaranteed to see the latest value written to the volatile variable. Without making the variable volatile, this would not be guaranteed.

事实上,当只有一个线程对volatile修饰的变量进行读写操作,并且其他线程仅仅只进行读操作时,那么就能保证读线程独到的必然是最新的值。若该变量没有被volatile修饰的话,就不能够保证。

4.Java 中能创建 volatile 数组吗?

能创建volatile数组,但volatile的作用并不能对数组中的元素生效,知识对该数组的引用生效(将数组看成是对象)

5.volatile 能使得一个非原子操作变成原子操作吗?

一个典型的例子是在类中有一个 long 类型的成员变量。如果你知道该成员变量会被多个线程访问,如计数器、价格等,你最好是将其设置为 volatile。为什么?因为 Java 中读取 long 类型变量不是原子的,需要分成两步,如果一个线程正在修改该 long 变量的值,另一个线程可能只能看到该值的一半(前 32 位)。但是对一个 volatile 型的 long 或 double 变量的读写是原子。

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

推荐阅读更多精彩内容