目录
线程的可见性是指当多个线程同时访问共享的变量时,一个线程对变量的修改能够被其他线程立即看到。如果没有正确处理线程的可见性,可能会导致数据不一致或者出现意料之外的结果。
下面我演示一下这个不可见性:
public class Concurrent2 {
static boolean a = true;
public static void main(String[] args) throws
InterruptedException {
new Thread(()->{
while(a){}
}). start();
Thread. sleep ( 1000);
a = false;
System.out.printIn(a);
}
}
这段代码创建了一个简单的多线程示例,主要包含两个线程:主线程和子线程。
在主线程中,首先创建了一个新的子线程,该子线程是通过lambda表达式创建的,其执行逻辑是在一个while循环中判断变量a的值是否为true,如果是true,则一直循环。这个while循环相当于一个空转操作,没有具体的业务逻辑。
接着,主线程通过Thread.sleep(1000)方法暂停1秒,以确保子线程能够启动并进入循环。
然后,主线程将变量a的值修改为false,并输出a的值。
运行演示:

当我们运行这个代码时我们发现,虽然输出了结果为false,但是这个程序并没有结束。因为主线程修改了变量a的值为false后,子线程并没有立即看到这个修改,导致子线程一直在循环中等待。因此,最终输出的结果是false,并且子线程并没有结束。(因为这个里面我们是一个空语句导致呢)
比如说我们就简单的在里面给他一定的时间
public class Test1 {
static boolean a = true;
public static void main(String[] args) throws
InterruptedException {
new Thread(() -> {
while (a) {
try {
Thread.sleep(1); //1毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
Thread.sleep(1000);
a = false;
System.out.println(a);
}
}
我们给了当前这个线程一定的喘息空间,让他能关取主存中a的最新值了,所以这个程序就执行完了

当一个线程修改了某个变量的值时,它会首先将该变量从主内存中拷贝到自己的工作内存中(即缓存),然后对该变量进行操作。操作完成后,线程会将变量的值写回主内存。其他线程在访问这个变量时,由于缓存的存在,可能会读取到过期的值,而不是最新的值。
那怎么解决这个不可见性呢
哎我们就添加这个volatile这个关键字,使得这个a是强制刷新
public class Test1 {
static volatile boolean a = true; //添加volatile 关键字
public static void main(String[] args) throws
InterruptedException {
new Thread(() -> {
while (a) {
}
}).start();
Thread.sleep(1000);
a = false;
System.out.println(a);
}
}
在主存和local catch(局部变量缓存)之间保证了强制的一 致性,如果我们一个线得进行了协变量,那立马能够刷新到其他的CPU核心的local catch中最新的值,所以其他的线程呢就一定策取到最新的这个变量的值。
local catch(局部变量缓存)
局部变量缓存(Local Variable Cache)是指在Java虚拟机的栈帧中,用于存储方法中的局部变量的一块内存区域。每个线程在执行方法时,都会为该方法分配一个栈帧,栈帧中包含了方法的参数、局部变量以及操作数栈等信息。
局部变量缓存是为了提高方法执行的效率而引入的。在方法执行过程中,局部变量的访问速度比全局变量(存储在堆内存中)要快很多。因此,Java虚拟机将方法的局部变量存储在栈帧中的局部变量缓存中,以便快速访问。
总之,局部变量缓存是为了提高方法执行效率而引入的一种机制,它存储了方法的局部变量的副本,并通过栈帧来管理和访问。了解局部变量缓存对于理解Java方法执行的机制和性能优化非常重要。
缓存在计算机体系结构中有多级,通常包括L1、L2、L3等多级缓存。这些缓存位于CPU内部,与主内存之间,用于加速数据的访问和提高计算机的性能。

问题:
在第一个例子里面a是放在线程私有的L3 cache里面的,如果要是a放在线程公有的L1 cache里面,thread1改a,也是先改cache里面的a,即使先不把a写回主存,thread2也能命中cache,那是不是就不会发生可见性问题了呢?
L1一定是core私有的有时候也叫L1 Cache为Local Cache, L2,L3,L4一般是多个核心共享的cache,也叫Shared Cache。你的问题因该就是如果变量缓存在Shared Cache而非Local Cache中,是不是就有可能避免可见性的问题。
硬件的资料纯讲硬件,编程的又把硬件部分笼统化了,最终也没有准确的答案。但是我们可以这样思考这个问题,如果cpu是16核的L2缓存可能是每两个核心共享的,L3可能是每4个核心共享的,L4可能是16个核共享的。如果线程共享变量是存到了L2L3L4中任意一个,其实都可能出现俩线程都可见的现象。但是并不能完全避免,因为L1一定是线程私有的,况且很多CPU芯片在设计的时候,L2是必须包含L1内容,L3包含L2,以此类推。也就是所有的读写都需要经过L1,这样的话,可见性问题还是会出现,这里的包含又叫严格包含
对于多核而言,这个多核的缓存确实很难界定是否满足可见性,如果是单核cpu是否在共享缓存中,所有线程可以不通过主存来刷新自己的取值,直接在缓存中读取,就没有了可见性的问题
本文围绕Java线程可见性问题展开,通过多线程示例演示了不可见性现象,即主线程修改变量值后子线程未立即看到。介绍了使用volatile关键字解决可见性问题,还阐述了局部变量缓存机制,最后探讨了不同缓存层级对可见性问题的影响。
&spm=1001.2101.3001.5002&articleId=133803591&d=1&t=3&u=bd5f90a626d14808a123b2dfad446818)
371

被折叠的 条评论
为什么被折叠?



