可见性问题

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++ 这样的操作。

为什么在前面示例中的死循环加入System.out.println()会发现即使不加volatile修饰符,t线程也能正确看到对run变量的修改?