Java并发中volatile和happen before是什么? - javarevisited


要了解happen before,需要首先了解如果多个线程访问同一个变量会发生什么问题?尤其是当一个线程写入该变量,而一个线程同时从该变量读取时。
例如,假设我们有以下由线程T1执行的代码(请注意,整数变量y在x之前初始化):

int y = 1;
int x = 2;

现在,我们还有另一段代码T2,它由另一个线程T2执行,在该线程中,两个变量的值都被打印出来(注意变量x在y之前打印):

System.out.print(x);
System.out.println(y);

屏幕上应该打印什么?如果此代码是由同一线程执行的,则可以保证将2和1打印出来,但是对于多个线程,则没有保证的行为。T2很有可能看不到T1所做的分配,而只为x和y输出0。 也可能只看到x或y的初始化并进行相应打印。 这是可怕的且不可预测的,想想如果X是您银行帐户中的钱,您肯定想要可预测的行为。那就是happen before需要做的事情

happen before提供了某种顺序和可见性保证:

[b]-“一个[/b]
volatile变量的
[b]写入将在另一个对该[/b]
volatile变量
[b]读取之前发生。”[/b]

-“同步块上的解锁将在另一个对其上锁之前发生。”

线程T1写入volatile变量的值也就是所有更改将在线程T2读取相同volatile变量时可见,线程T1解锁之前,对T2在同一锁监视器内的锁进行上锁之前也是可见的。(这样通过前后关系保证了T1和T2两个线程操作同一个资源的先后顺序)

落实到前面代码,修改如下:

T1:
int y = 1;
[b]volatile [/b]int x = 2;  

T2:
System.out.print(x);
System.out.println(y);

增加了volatile 变量修饰之后,建立了两个线程的happen before先后顺序。

这时,T2肯定是输出了x=2的结果,因为它见到了T1的所有更改结果,这是volatile 作用,那么结果是
2和1或2和0?

如果您在T1进行volatile变量写入而T2进行volatile变量读取之前应用了happens-before这样关系,那么它还将看到y = 1的值,虽然没有使用volatile修饰符。

最后结果是确定的2和1。

这里要记住的关键是,线程T2甚至可以看到非易失性volatile变量的值。这里只是发生happens-before关系的一个示例,但在分析多线程程序的行为时非常有用。