并发编程系列之变量可见性问题探究 1、什么是并发中的变量可见性问题 以例子的形式看看,定义一个变量,先用static修饰,在主线程修改之后,看看在新开的子线程里能被看到? pu
并发编程系列之变量可见性问题探究
1、什么是并发中的变量可见性问题
以例子的形式看看,定义一个变量,先用static修饰,在主线程修改之后,看看在新开的子线程里能被看到?
public class Example {private static boolean flag = true;
public void testss() {
new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while (IfTest.flag) {
i++;
}
System.out.println(i);
}
}).start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
IfTest.flag = false;
System.out.println("设置flag");
}
}
执行,控制台打印:
设置flag
ps:主线程对flag变量进行修改,子线程是不能看到的,所以里面一直在循环,不能打印统计数据值。然后怎么才能让并发线程看见?
- 方式1:使用volatile关键字
private static volatile boolean flag = true;
public void testss() {
new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while (IfTest.flag) {
i++;
}
System.out.println(i);
}
}).start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
IfTest.flag = false;
System.out.println("设置flag");
}
}
控制台打印:
设置flag
72071943
- 方式2:使用synchronized同步锁
private static boolean flag = true;
public void testss() {
new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while (IfTest.flag) {
synchronized (this) {
i++;
}
}
System.out.println(i);
}
}).start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
IfTest.flag = false;
System.out.println("设置flag");
}
}
控制台打印:
设置flag
86726163
2、什么是Java内存模型?
解答这个问题,需要涉及到Java的内存模型,如下所示,Java内存模型及操作规范:
在这里插入图片描述
- Java内存模型的同步交换协议,规定了8种原子操作
原子操作:不可被中断的一个或一系列操作
- Java内存模型的同步交互协议,执行上述8种原子操作时必须满足如下规则
- Java内存模型的同步协议,操作规范
图引用网上资料:
在这里插入图片描述
3、保证变量可见性的方法
4、Synchronized怎么做到可见性
- synchronized语义规范:
- synchronized是如何做到线程安全的?
5、volatile关键字解密
- volatile语义规范:
- volatile可以做到线程安全?
不能,因为volatile没有锁机制,线程是可以并发操作共享资源的 - volatile相对synchronized有什么优点?
- volatile的使用场景?
- volatile支持并发编程三大特效?
并发编程三大特效:原子性、有序性、可见性。