Volatile

Volatile

vloatile关键字是Java虚拟机提供的最轻量级的同步机制,本文介绍volatile的作用和底层实现原理。

1、volatile解决线程安全性问题

我们说过,在多线程中存在竟态条件,会出现线程安全性问题

volatile关键字作用是保证可见性和有序性,并不会保证原子性。

volatile可以解决可见性问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class ThreadDemo1 implements Runnable{

public volatile boolean flag = false;

@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

flag = true;

}
}


public class safeVolatileDemo1 {

public static void main(String[] args) {

ThreadDemo1 threadDemo1 = new ThreadDemo1();
Thread thread = new Thread(threadDemo1);
thread.start();

while(true){
if (threadDemo1.flag == true){
System.out.println("ThreadDemo1.flag = true");

break;
}
}
}
}
volatile解决重排序问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.jiang.ThreadSafe.safeVolatile;

/**
* 重排序可能会带来的问题
*/
public class safeVolatileDemo2 {
private volatile static int x = 0, y = 0;
private volatile static int i = 0, j = 0;

public static void main(String[] args) throws InterruptedException {
int count = 0;
while(true){
count++;
x = 0;
y = 0;
i = 0;
j = 0;

Thread one = new Thread(new Runnable() {
@Override
public void run() {
i = 1;
x = j;
}
});
Thread two = new Thread(new Runnable() {
@Override
public void run() {
j = 1;
y = i;
}
});
two.start();
one.start();
one.join();
two.join();

String result = "第" + count + "次(" + x + "," + y + ")";
if (x == 0 && y == 0) {
System.out.println(result);
break;
} else {
System.out.println(result);
}
}
}
}
1
# 一直循环

image-20210419104609298

2、volatile作用

在Happens-before先行发生原则中,有对volatile字段的描述

对某个volatile字段的写操作happens-before(先行于)每个后续对该volatile字段的读操作

对于一个线程对由volatile字段修饰的变量进行读操作时,直接读取主内存中的数据,进行写操作,直接写到主内存中。

使用volatile修饰字段之后:

  1. 修改的值会立即写回主存

  2. 修改值之后,其他线程中的工作内存的数据置为无效(在CPU缓存时提到,MESI会将数据设置为四种状态)

  3. 工作内存中数据无效,会直接读取主内存中的数据

3、volatile原理

加入volatile关键字时,所生成的汇编代码会多出一条lock前缀指令

​ 这一条指令实际上相当于一个内存屏障(也称为内存栅栏),内存屏障会提供三个功能:

  1. 确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面。即在执行到内存屏障这句指令时,在它前面的操作已经全部完成

  2. 它会强制将对缓存的修改操作立即写入主存

  3. 如果是写操作,他会导致其他CPU中的对应的缓存行无效


Volatile
https://johnjoyjzw.github.io/2021/01/03/volatile/
Author
John Joy
Posted on
January 3, 2021
Licensed under