avatar

从i++的线程安全问题,分析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
package com.wzl.day26;

/**
* @ClassName VolatileVisibility
* @Description VolatileVisibility
* @Author wuzhilang
* @Date 2021/1/10 17:09
* @Version 1.0
*/
public class VolatileVisibility {
public static volatile int i = 0;
public static void increase(){
i++;
}
/**
* 在并发场景下,i变量的任何改变都会立马反应到其他线程中,但是如此春仔多条线程同时调用increase()方法的话,就会出现线程安全问题,毕竟i++;操作
* 并不具备原子性,该操作是先取值,然后写回一个新值,相当于原来的值上加1,分两步完成如果第二个下城在第一个编程读取旧值和写会新值期间读取i的域值,
* 那么第二个线程就会与第一个线程一起看到同一个值,并执行相同值的加1操作,这就就造成了线程安全失败,因此对于,increase方法必须使用synchronized
* 修饰,以便保证线程安全,需要注意的是一旦使用synchronized修饰方法后,由于synchronized本身也具备与volatile相同的特性,即可见性,因此在
* 这种情况下就可以完全省去volatile修饰的变量。
*/


}

volatile的内存语义

volatile是java虚拟机提供的轻量级的同步机制。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
36
37
38
39
40
41
package com.wzl.day26;

/**
* @ClassName VolatileVisibilitySample
* @Description VolatileVisibilitySample
* @Author wuzhilang
* @Date 2021/1/10 16:42
* @Version 1.0
*/
public class VolatileVisibilitySample {
volatile boolean initFlag = false;
public void sava(){
this.initFlag = true;
String threadname = Thread.currentThread().getName();
System.out.println("线程:" + threadname + ":修改共享变量initFlag");
}
public void load(){
String threadname = Thread.currentThread().getName();
while (!initFlag){
//线程在此处空跑,等待initFlag状态改变
}
System.out.println("线程:" + threadname + "当前线程嗅探到initFlag状态的改变");
}

public static void main(String[] args) {
VolatileVisibilitySample sample = new VolatileVisibilitySample();
Thread threadA = new Thread(()->{
sample.sava();
}, "threadA");
Thread threadB = new Thread(()->{
sample.load();
},"threadB");
threadB.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
threadA.start();
}
}
文章作者: 无知的小狼
文章链接: https://bytedance.press/2021/01/10/20210101/volatile%E5%85%B3%E9%94%AE%E5%AD%97/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 无知的小狼

评论