Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/322.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 一个线程中非易失性成员变量的赋值是否保证在另一个线程中看到?_Java_Multithreading_Java Memory Model - Fatal编程技术网

Java 一个线程中非易失性成员变量的赋值是否保证在另一个线程中看到?

Java 一个线程中非易失性成员变量的赋值是否保证在另一个线程中看到?,java,multithreading,java-memory-model,Java,Multithreading,Java Memory Model,考虑下面的Java示例。请注意,两个类成员变量均未声明为易失性。如果我正确理解内存模型和“之前发生”规则,Java实现可以优化run()方法,使其永远运行,即使另一个线程调用stopNow()方法。这可能是因为run()方法中没有强制线程多次读取stop的值的内容。对吗?若否,原因为何 class Example implements Runnable { boolean stop = false; int value = 0; public void stopNow(

考虑下面的Java示例。请注意,两个类成员变量均未声明为
易失性
。如果我正确理解内存模型和“之前发生”规则,Java实现可以优化
run()
方法,使其永远运行,即使另一个线程调用
stopNow()
方法。这可能是因为
run()
方法中没有强制线程多次读取
stop
的值的内容。对吗?若否,原因为何

class Example implements Runnable {
    boolean stop = false;
    int value = 0;

    public void stopNow() {
       stop = true;
    }

    public int getValue() {
        return value;
    }

    @Override
    public void run() {
        // Loop until stop is set to true.
        while (!stop) {
            ++value;
        }
        return;
    }
}

没错。这就是您可能希望使用另一个线程可以修改的
volatile

的原因之一,但这不是gurranteed。而且这也不是线程安全的。要使变量gurranteed从另一个线程查看,您需要执行以下任一操作

一个线程对字段所做的更改保证对用户可见 其他螺纹仅在以下条件下使用:

  • 写入线程释放同步锁,读取线程随后获取相同的同步锁
  • 如果某个字段被声明为volatile,写入该字段的任何值都将被刷新,并在写入程序之前由写入程序线程显示
    线程执行任何进一步的内存操作(即,出于以下目的
    手边立即冲洗)。读卡器线程必须重新加载
    每次访问时易失性字段的值
  • 线程第一次访问对象的字段时,会看到字段的初始值或由 其他的线
  • 当线程终止时,所有写入的变量都会刷新到主存。例如,如果一个线程在 使用thread.join的另一个线程,则保证可以看到
    该螺纹产生的影响(见§4.3.2)

有帮助的

购物应该是正确的,是的。我不确定这是一个“可以”还是“必须”的问题,所以第三方虚拟机可能会有不同的处理方式。也许你可以在这里回答这个问题。为什么在调试模式下,如果在另一个线程中的
stop
被转到
true
后,在
run()
内部阻塞了
run()
,则执行
run()
的线程会将其值视为
true
?Java的调试模式是否强制刷新该值?如果可以,有没有办法在正常模式下这样做?如果有,那么你的答案会错吗?@SotiriosDelimanolis程序员通常最关心的是他们能依靠什么,而不是工作中会发生什么。@BrianRoach这个问题发布后,我就一直在运行它,而字段还没有同步。@BrianRoach问题是他能依靠什么,而不是你认为可能发生什么。你怎么知道当他升级他的CPU,操作系统,我们的Java版本时会发生什么?你为什么要鼓励他编写脆弱的、破损的代码?@BrianRoach“它可能会运行更长的时间,因为它读取了N次过时的停止值,但最终缓存会同步。”这是完全错误的。几乎所有现代缓存在硬件上都是即时一致的。这与缓存无关。有趣的是,即使
stop
被更改为公共成员,并且在while循环中调用了另一个类或包中的方法,仍然没有Java语言要求从内存中再次获取
stop
的值。但我确实认为编译器需要检查被调用的代码,才能知道这样的优化是安全的。在没有彻底分析的情况下,编译器可能不会优化掉
stop
@DarylOdnert”的内存获取。编译器需要检查调用的代码,以知道这样的优化是安全的“=>不,不会:内存模型允许不从内存读取它,所以即使它导致错误(我想这是你对安全的定义)它是允许的。如果没有volatile,唯一的保证就是程序顺序,每个线程。@assylias-听起来不对。如果while循环包含函数调用(将
作为参数传递)被调用的函数修改了this.stop
,内存模型说必须识别更新,因为赋值发生在同一个线程中。我是否遗漏了什么?@DarylOdnert如果一个方法修改了线程T1中的stop,那么在T1中运行的任何后续代码都可以看到更改-但这并不意味着该值是f从内存中蚀刻…如果线程T2随后读取stop,则可能看不到新值。如果T3之前修改了stop,则可能无法从T1中看到它…@DarylOdnert不一定-这取决于T1何时启动。如果T1在T3中写入stop后启动,则会看到它。否则,T1可能会看到默认值(false),或stop在某个时间具有的其他值,或最近的值。两者都是可能的且允许的。