2010-03-31 73 views
3

考虑下面的Java代码:!不同!易变的变量?

volatile boolean v1 = false; 
volatile boolean v2 = false; 

//Thread A 
v1 = true; 
if (v2) 
    System.out.println("v2 was true"); 

//Thread B 
v2 = true; 
if (v1) 
    System.out.println("v1 was true"); 

如果有挥发性访问全局可见总订货则至少有一个的println总是到达。

这实际上是由Java标准保证的吗?或者是这样的可能执行:

A: v1 = true; 
B: v2 = true; 
A: read v2 = false; 
B: read v1 = false; 
A: v2 = true becomes visible (after the if) 
B: v1 = true becomes visible (after the if) 

我只能找到报表有关访问的标准相同 volatile变量(但我可能失去了一些东西)。

“写入易失性变量(§8.3.1.4)v与任何线程(随后根据同步顺序定义的内容)随后对v的所有后续读取进行同步。”

http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.4.4

谢谢!

+0

是的,它的确如此。这个问题是http://stackoverflow.com/questions/2441279/java-volatile-guarantees-and-out-of-order-execution的副本 – 2010-03-31 18:33:47

回答

1

我认为报价回答您的问题比你更认识它。

在线#2中线程Bv2的写入在尝试读取变量时由线程A“看到”。

我加粗报价的关键部分:

“到volatile变量的写(§8.3.1.4)V同步所有后续的任何线程读取诉...“

+0

@matt b:是的,但它比这更复杂:如果在线程A中发生重新排序,该怎么办? (看起来我的回答是真正的评论)。我认为在这种情况下重新排序是非法的......但是这句话当然没有多说这些。 – SyntaxT3rr0r 2010-03-31 19:28:18

+0

重新排序哪些语句?通常“重新排序”适用于在方法或代码块内对语句进行重新排序以改变操作顺序。 JVM只允许重新排列不会影响后续语句的语句。在你的线程中,唯一需要重新排序的是赋值和对另一个变量的检查 - 在线程run()中重新排序这两个语句不会影响任何内容。 – 2010-03-31 19:32:44

0

由于v2volatile这一事实,执行中的第三行是不可能的。

如果v2不是volatile,线程A可以看到v2的本地缓存副本,该副本仍然是false

由于v2是易失性的,但是,每次读取都会直接进入主存储器,因此会看到最近写入的值。这就是说,我不相信在访问不同的全局变量之间有任何特定的顺序保证,但我也不相信这会对你的例子产生影响。

-1

那么......如果v2被B设置为true,那么通过volatile的定义,那么A就不能将其读为false。

挥发性使得数据类型和引用线程工作时做单opeartions时如预期(所以++和 - !不工作)

+1

这也适用于64位长的 – 2010-03-31 20:19:00

+0

你是对的:http: //mindprod.com/jgloss/volatile。html在Java 1.5中进行了更改 – Pyrolistical 2010-03-31 22:02:32

-1

这太长评论(这只是一个可能的重新排序的情况下注释),但我认为以下是可能如果你只有一个线程

A: read v2 = false; 
A: v1 = true; 

的”阅读“(如果)可以在作业前发生(如果它对接下来的内容没有影响)。 10以下不能发生:

A: read v2 = false; 
A: v1 = true; 
B: read v1 = false; 
B: v2 = true; 

这是不可能的,因为你有两个线程,因此这些线的人可能检测出重排有这样的重新排序,使得该编译器重新排序非法的。

我在这里问类似,但绝对不相同的一个问题(在同一个线程写a和b,从不同的线程读取):

Volatile guarantees and out-of-order execution

1

4分的动作,V1的挥发性读/写/ v2,都是同步操作。执行对它们有一个同步顺序,这是一个总的顺序。订单必须保持每个线程的程序顺序。

这使得推理非常简单。显然,至少对于2个变量中的1个,在'同步顺序'中对它的写入是在读取它之前进行排序的。因此,写入'与'同步'读取。因此,写入'发生在'读取之前。因此,写入对读取是可见的。

0

简而言之:至少会打印一次,因为两个易失性操作不能重新排序。

我不知道它在说明书中写的是什么,但在Doug Lea网站上有一个表格,哪些操作可以重新排序,哪些不可以。 (http://gee.cs.oswego.edu/dl/jmm/cookbook.html


这种情况是不可能的,因为读是初始化发生之前线程开始

错了!

A: v1 = true; 
B: v2 = true; 
A: read v2 = false; // initialization happens before thread start 
B: read v1 = false; // initialization happens before thread start 

您的情况可能的,如果只有在这种情况下,这是不可能的,因为v2和V1是易失性写V1必须阅读之前V2写V2前必须读取v1

错误!

volatile boolean v1 = false; 
volatile boolean v2 = false; 

//Thread A 
if (v2) //read v2 
    System.out.println("v2 was true"); 
v1 = true; //write to v1 

//Thread B 
if (v1) //read v1 
    System.out.println("v1 was true"); 
v2 = true; //write v2