可见性问题
package org.example;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
@Slf4j
public class Main {
static boolean visibity = true;
public static void main(String[] args) {
new Thread(() -> {
while (visibity) {
}
log.info("fdsafasfds");
}).start();
try {
TimeUnit.SECONDS.sleep(1);
visibity = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
JMM主内存与工作内存
JMM 定义了一种抽象的结构,包含主内存 (Main Memory) 和工作内存 (Working Memory):
主内存 (Main Memory):
是所有线程共享的区域。
存储了所有的实例字段、静态字段以及构成数组对象的元素。
可以把它想象成一个中央仓库。
工作内存 (Working Memory):
每个线程都有自己独立的工作内存。
存储了该线程使用的变量的主内存副本拷贝。
线程对变量的所有操作(读取、赋值等)都必须在自己的工作内存中进行,不能直接读写主内存中的变量(除了特定指令)。
不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。
可以把它想象成每个工人的私人工作台,工人从中央仓库领材料(变量副本)到自己工作台加工。
解决办法 加volatile
package org.example;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
@Slf4j
public class Main {
static volatile boolean visibity = true;
public static void main(String[] args) {
new Thread(() -> {
while (visibity) {
}
log.info("fdsafasfds");
}).start();
try {
TimeUnit.SECONDS.sleep(1);
visibity = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
volatile
核心作用
可见性保证:当一个线程修改了 volatile 变量的值,这个新值对于其他线程来说是立即可见的。Java 内存模型确保所有线程看到的 volatile 变量值是最新的。
禁止指令重排序:volatile 关键字禁止了指令重排序,确保了程序执行的顺序性。
不保证原子性:volatile 不能保证复合操作的原子性,例如 i++ 这样的操作。