提问者:小点点

同步进入、退出和易失性读写时的缓存刷新


同步块执行完成后,将刷新所有处理器缓存,还是仅刷新对其执行同步语句操作的对象?在下面的示例中,当线程完成 method2 的执行时,obj2 的数据是否也会刷新到主内存?

class cls1 {
    int x=10;
}

class cls2{
    int y=10;
}

class cls3{
    cls1 obj1;
    cls2 obj2;
    public void method2(){
        obj2.y=10;
        synchronized(obj1){
            obj1.x=30;
        }
    }

    public static void main(String[] args) {
        final cls3 obj3 = new cls3();

        Thread thread1 = new Thread(){
            public void run(){
                obj3.method2();
            }
        };
        Thread thread2 = new Thread(){
            public void run(){
                System.out.println(obj3.obj1.x);
            }
        };
    }
}

共3个答案

匿名用户

只有当另一个线程也对第一个线程用来更新内容的锁进行同步时,才会在建立关系之前发生。

在这个例子中,线程B在获取了相同对象M上的锁之后,将能够看到在同步块之前和期间所做的所有改变。但是请记住,必须获得锁才能发生发生前关系。

在您的示例中,因为System.out.println(obj3.obj1.x)不是在同步块中打印的,它不能保证以前发生过。

参考文献:

  • http://www.ibm.com/developerworks/library/j-jtp03304/

编辑:Peter的回答很好当使用volatile和synchronized时,刷新或发布到各种线程的内存范围是什么?

匿名用户

当同步块执行完成时,所有处理器缓存都被刷新,还是只有同步语句所作用的对象被刷新?

快速回答:处理器缓存中的所有脏块都会被刷新。

当线程进入一个< code>synchronized块时,它会越过一个读内存屏障,这会导致已经在主内存中更新的内存的本地副本从本地处理器内存缓存中被刷新。

当线程退出< code>synchronized块时,它会越过写内存屏障,所有本地处理器脏块都会被写入主内存。这不仅仅是锁对象,而是所有脏内存块。

在下面的示例中,当线程完成了方法2的执行时,对象2的数据是否也会刷新到主存储器中?

是的。当线程退出时,还会跨越一个写内存障碍。

< code > system . out . println(obj 3 . obj 1 . x);

这可能不会打印 30。重要的是要认识到:

  • 您的代码中不能保证thread2会在thread1完成后运行。即使您在thread1之后启动thread2,竞争条件也可能在thread1更新它或将缓存刷新到中央内存之前发生thread2访问。
  • 此外,即使您保证thread2代码在thread1完成后确实运行,您也需要确保thread2本身穿过读取内存屏障以从主存中读取

在 2 个线程之间共享数据时,必须确保操作顺序正确,并考虑内存同步。

匿名用户

JLS 没有谈论缓存及其一致性,它使用“发生之前”关系来建立线程间操作的顺序,例如对共享内存的读取和写入。在您的示例中,允许对 obj2.y=10 重新排序,以便它在同步块之后。此外,由于没有通过方法输入/退出建立“发生之前”,因此JMM无法保证更改在方法完成后变得可见。

有关底层原理的详细解释,请参见Java规范的“Java内存模型”。

顺便说一句,您似乎忘记在main中创建的线程实例上调用start()方法。