需要帮助了解java中多线程时的内存可见性问题吗
我将在实践中学习Goetze的Java并发性,并且在不使用synchronized关键字时,仍停留在共享变量的内存可见性部分 代码如下需要帮助了解java中多线程时的内存可见性问题吗,java,multithreading,Java,Multithreading,我将在实践中学习Goetze的Java并发性,并且在不使用synchronized关键字时,仍停留在共享变量的内存可见性部分 代码如下 public class NoVisibility { private static boolean ready; private static int number; private static class ReaderThread extends Thread { public void run() {
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while(!ready)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args){
new ReaderThread().start();
number=42;
ready=true;
}
}
作者说这个类可能永远循环,因为ready的值可能永远不会被读者线程看到
我不明白这种说法
在我看来,首先主线程启动并设置数字,然后准备为true。但是另一个线程有它自己的堆栈和它自己的number和ready值,它不与主内存同步,这两个线程只有它们自己的变量副本
现在,readerthread应该永远保持在循环中。我想知道为什么Thread.yield
变量不会屈服于主线程,然后主线程应该刷新到主内存,然后readerthread应该获取这个新值并终止循环并打印正确的值,因为它也应该同步
所以我想我有一些问题是
cpu缓存中的值与主内存刷新/同步的频率是多少 该值是否可以与主内存不同步?这也是一种可能性吗 为什么会发生这种情况 当只有一个cpu核心和一个cpu缓存时,这种内存可见性是否也会发生,还是总是发生 虽然我了解竞争条件和死锁,但我在理解内存可见性问题时遇到了一些困难。这是特定于架构的吗
cpu缓存中的值与主内存刷新/同步的频率是多少 未定义。当JLS中指定的可见性保证表示需要进行缓存刷新时,就会发生缓存刷新 该值是否可以与主内存不同步?这也是一种可能性吗 对 为什么会发生这种情况 一般来说,缓存被刷新是有原因的。“发生在”关系指示可能需要缓存刷新的位置 当只有一个cpu核心和一个cpu缓存时,这种内存可见性是否也会发生,还是总是发生 如果只有一个核心,则缓存刷新不是问题1 虽然我了解竞争条件和死锁,但我在理解内存可见性问题时遇到了一些困难。这是特定于架构的吗 是和否。内存可见性可能因硬件体系结构和其他因素而有所不同,但编写代码以提供定义良好的行为的方法与体系结构无关 如果您确实需要深入了解内存可见性问题,则需要了解内存模型。Goetz等人在第16章中以外行术语对其进行了描述,并在JLS中进行了规定
我想知道为什么
Thread.yield()
调用不会向主线程屈服,然后主线程应该刷新到主内存
Thread.yield()
可能会让位于另一个可运行线程。但是,在调用yield()
时,main
线程很可能不再可运行。(或者它可能仍在运行。)yield()
不会在主线程和子线程中的任何语句之间创建一个before。如果没有关系之前发生的情况,则运行时没有义务确保主线程的赋值结果对子线程可见Thread.yield()
可能执行缓存刷新2,但它将刷新子线程的缓存,而不是父线程的缓存1-实际上,这可能过于简化了。例如,在一个系统中,一个内核和多个具有自己缓存的超线程,需要进行缓存刷新
2-例如,如果
yield()
确实导致上下文切换,那么上下文切换通常包括缓存刷新,作为操作系统执行的线程状态保存的一部分。但是,yield()
不一定会导致上下文切换。此外,JLS没有指定此方面。字段可见性意味着线程观察者字段值来自缓存内存,并且可以与CPU另一个核心中的其他缓存具有不同的状态。JVM不保证访问共享资源的不同线程的字段可见性,程序员需要使用sycchronized来防止读取错误的状态,或者使用volatile来保证将更改刷新到其他缓存。“cpu缓存中的值与主内存刷新/同步的频率是多少?”不少于内存模型要求的频率。这不是“多少次”的问题。“我想知道为什么Thread.yield变量不会屈服于主线程,然后主线程应该刷新到主内存…”可见性是关于发生之前的关系。只有当写入发生在读取之前,即创建“发生在发生之前”关系的操作时,写入才会保证可见Thread.yield()
不会创建“先发生后发生”关系。我要明确补充的是,Thread.yield()
不会创建“先发生后发生”关系,因为OP会问为什么这不能解决问题-实际上不需要根据文档做任何事情。即使它确实创建了一个HB,它也只会自己创建一个HB,因为在Thread.start()
之后没有其他操作创建HB,而yield()
。