- 可见性问题描述
@Slf4j(topic = "c.Test32")
public class Test32 {
// 易变
static boolean run = true;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while(true){
if(!run) {
break;
}
}
});
t.start();
sleep(1);
run = false; // 线程t不会如预想的停下来
}
}
-
上述代码,由于t线程需要频繁的访问主存中的run值,JIT会讲run值添加到t线程中的缓存中,这样主线程修改了run的值,t线程并没有重新从主存中获取,因而t线程不会停下来,如下图所示
-
解决:添加易变关键字 volatile:加了这个关键字的修饰,表示这个变量容易发生变化,因此不能读取到线程的工作缓存中,需要每次从主存中获取
@Slf4j(topic = "c.Test32")
public class Test32 {
// 易变 volatile:加了这个关键字的修饰,表示这个变量容易发生变化,因此不能读取到线程的缓存中,需要每次从主存中获取
volatile static boolean run = true;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while(true){
if(!run) {
break;
}
}
});
t.start();
sleep(1);
run = false; // 线程t不会如预想的停下来
}
}
- 使用synchronized关键字可以保证可见性和原子性,但是此关键词属于重型操作,性能较低
@Slf4j(topic = "c.Test32")
public class Test32 {
// 易变 volatile:加了这个关键字的修饰,表示这个变量容易发生变化,因此不能读取到线程的缓存中,需要每次从主存中获取
volatile static boolean run = true;
static final Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while(true){
synchronized (lock) {
if (!run) {
break;
}
}
}
});
t.start();
sleep(1);
synchronized (lock) {
run = false; // 线程t不会如预想的停下来
}
}
}