Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.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 如果getter被标记为synchronized,为什么此代码会结束?_Java_Multithreading_Synchronized_Non Volatile - Fatal编程技术网

Java 如果getter被标记为synchronized,为什么此代码会结束?

Java 如果getter被标记为synchronized,为什么此代码会结束?,java,multithreading,synchronized,non-volatile,Java,Multithreading,Synchronized,Non Volatile,当方法get()被标记为已同步时,尽管字段值不是易失性的,为什么此代码成功完成?如果没有同步,它将在我的机器上无限期运行(如预期的那样) 同步强制this.value=value发生在get()之前 它确保更新值的可见性 没有同步,就没有这样的保证。它可能工作,也可能不工作。对于初学者来说,值需要是易失性的,或者获取和设置都需要是同步的,这才是正确的 JLS 17.4.5: 监视器上的解锁发生在监视器上的每个后续锁定之前 在释放锁之前,value可以设置为5,这会将其置于发生之前边缘之前,并使其

当方法
get()
被标记为已同步时,尽管字段值不是易失性的,为什么此代码成功完成?如果没有同步,它将在我的机器上无限期运行(如预期的那样)


同步强制
this.value=value
发生在
get()
之前

它确保更新值的可见性


没有同步,就没有这样的保证。它可能工作,也可能不工作。

对于初学者来说,
需要是
易失性的
,或者
获取
设置
都需要是
同步的
,这才是正确的

JLS 17.4.5:

监视器上的解锁发生在监视器上的每个后续锁定之前

在释放锁之前,
value
可以设置为
5
,这会将其置于发生之前边缘之前,并使其在下次获取锁时可用

应该注意的是,这种保证是脆弱的,并且取决于线程调度程序,可能根本不存在。在同步模型较弱的平台上,可能看不到与此处相同的效果


另见:


安迪·特纳部分正确

get()
方法上添加
synchronized
会影响内存可见性要求,并导致(JIT)编译器生成不同的代码

但是,严格地说,在连接
set(…)
调用和
get()
调用之前需要有一个发生关系。这意味着
set
方法应该是
synchronized
以及
get
(如果要这样做的话!)

简言之,您观察到的代码版本不能保证在所有平台和所有情况下都能工作。事实上,你很幸运


从字里行间看,您似乎在试图通过实验了解Java的内存模型是如何工作的这不是一个好主意。问题在于,您正试图对一个极其复杂的黑匣子进行反向工程,但没有足够的“输入参数”1供您更改以涵盖黑匣子行为的所有潜在方面

因此,“通过实验学习”的方法很容易让你产生不完整或错误的理解

如果您想全面准确地理解,应该从阅读一本好的教科书中有关Java内存模型的内容开始。。。或者JLS本身。无论如何,使用实验来确认您的理解,但是您确实需要知道JMM只指定(保证)如果您做正确的事情会发生什么。如果你做了错误的事情,你的代码可能仍然有效。。。取决于各种因素。因此,通常很难从实验上确认某一特定的做事方式是正确的还是不正确的2

1-一些您需要的参数实际上并不存在。例如,一个允许您运行Java N For N>12,或者一个允许您在您无权访问的硬件上运行。。。或者那还不存在


2-如您的示例所示。您得到的答案是“正确的”,即使代码是错误的。

如果没有正确的同步,程序结果是不确定的。程序可以正确运行和完成,也可以不正确,这完全取决于JVM实现的突发奇想(该实现可能随时发生变化)。这是一个非常详细和正确的解释,应该标记为正确答案。感谢您提供了完整的答案@Stephen!我知道这段代码是坏的(无论是否在getter上同步),我绝对不会在生产中使用类似的东西。
public class MtApp {

    private int value;

    /*synchronized*/ int get() {
        return value;
    }

    void set(int value) {
        this.value = value;
    }

    public static void main(String[] args) throws Exception {
        new MtApp().run();
    }

    private void run() throws Exception {
        Runnable r = () -> {
            while (get() == 0) ;
        };
        Thread thread = new Thread(r);
        thread.start();
        Thread.sleep(10);
        set(5);
        thread.join();
    }
}