专栏名称: OSC开源社区
OSChina 开源中国 官方微信账号
目录
相关文章推荐
伯乐在线  ·  赔偿 N+3!TP-Link WiFi ... ·  14 小时前  
伯乐在线  ·  赔偿 N+3!TP-Link WiFi ... ·  14 小时前  
OSC开源社区  ·  全球首个基于Web的“液态玻璃(Liquid ... ·  昨天  
程序员的那些事  ·  离谱!裁员裁出新高度了。。。 ·  昨天  
程序员的那些事  ·  安卓重大更新!Android 16 ... ·  2 天前  
OSC开源社区  ·  那个苹果史上最有品味的程序员去世了 ·  3 天前  
51好读  ›  专栏  ›  OSC开源社区

Java 多线程 —— 深入理解 volatile 的原理以及应用

OSC开源社区  · 公众号  · 程序员  · 2017-09-07 08:30

正文

请到「今天看啥」查看全文


第一种情况:

线程A先执行write方法之后,线程B执行read方法。那么:

1、基于程序次序法则。 1 happens-before 2; 3 happens-before 4

2、基于volatile原则。 2 happens-before 3;

3、基于传递性原则。 因为 1 happens-before 2,2 happens-before 3,3 happens-before 4。那么可以推断出 1 happens-before 4,2 happens-before 4。

此种情况下,我们可以认定此时线程B中可以读取到 线程A中写入的 a和b的值的。(a值没用声明volatile依然可以读取到,这个为何我们后面讲)

第二种情况:

线程B先执行read方法,之后线程A执行write方法。

1、基于程序次序法则。3 happens-before 4; 1 happens-before 2

2、基于volatile原则。无;

3、基于传递性原则。无传递;

此种情况下,我们可以此时认定线程B中没有读取到线程A中写入的a和b的值。

通过上面的分析我们可以对volatiel变量如此定义:

  • 当write一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。

  • 当read一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。

对于第一种情况,我们看上述示例如何write和read的:

那么读到这里,有一个困惑:上述变量a并没有声明为volatile ,为何能被刷新到主内存中,难道不会被处理器重排序么?

二、volatile限制重排序


上述中我们讲到volatile 中有一个特性,有序性,防止jvm对其重排序,那么究竟是如何做的,我们看一下。

重排序分为编译器重排序和处理器重排序。为了实现volatile内存语义,jvm会分别限制这两种类型的重排序类型。

编译器重排序

针对编译器制定的volatile重排序规则:

上述表中,NO表示jvm不可以重排序,保持当前顺序。

比如第一行第三列中表示:第一个操作是变量的普通读写,第二个操作是volatile声明的变量写操作,那么此时对于操作1和操作2是不可以重排序的,保持当前顺序。

就好比上述示例中a 和b变量,满足此种情况,a和b的操作顺序不变。

上述规则用文字描述:

  • 当第二个操作是volatile写时,不管第一个操作是什么,都不能重排序。这个规则确保volatile写之前的操作不会被编译器重排序到volatile写之后。

  • 当第一个操作是volatile读时,不管第二个操作是什么,都不能重排序。这个规则确保volatile读之后的操作不会被编译器重排序到volatile读之前。







请到「今天看啥」查看全文