我找过一个 置的代 报告在我的代码基地和一个模式,是引发的是一个空的 synchronzied 方块(即 synchronized (var) {}).的 文件说:

空同步块更多 微妙和难以使用正确比 大多数人认识到,空 同步块几乎从来没有一个 更好的解决方案比较不做作 解决方案。

在我的情况下,它的发生是因为块的内容已经说了,但是 synchronized 声明仍然存在。在什么情况下可能有空 synchronized 框实现正确的穿语?

有帮助吗?

解决方案

一个空同步块将等待,直到没有其他人正在使用该同步器。这可能是你想要什么,而是因为你没有在synchronized块保护后面的代码,没有从修改过什么是你在等待的同时运行后续代码阻止其他人。这是几乎从来没有你想要的东西。

其他提示

先前的答案未能强调,最有用的东西有关空 synchronized 模块:他们可以确保能见度的变量变化和其他行动跨线。作为 jtahlborn 指示,同步规定,"记忆屏障"上编译器,迫使它冲洗和刷新其缓存。但我没找到这里的"蛇讨论了"这,所以我写了回答我自己。

int variable;

void test() // This code is INCORRECT
{
    new Thread( () ->  // A
    {
        variable = 9;
        for( ;; )
        {
            // Do other stuff
        }
    }).start();

    new Thread( () ->  // B
    {
        for( ;; )
        {
            if( variable == 9 ) System.exit( 0 );
        }
    }).start();
}

上述程序是不正确的。值的变量可能会缓存在本地的在线A或B或两者。所以,B可能永远不会阅读值的9个写道,和可能因此循环永远。

做一个变量的变化可见的在线程通过使用空 synchronized

一个可能的修正添加一个 volatile (有效地"没有高速缓冲存储器")修改的变量。有时候,这是效率低下,然而,因为它完全禁止缓存的变量。空 synchronized 块,另一方面,不要禁止缓存。他们所要做的就是力的高速缓存同步主要存在某些关键点。例如:*

int variable;

void test() // Corrected version
{
    new Thread( () ->  // A
    {
        variable = 9;
        synchronized( o ) {} // Flush to main memory
        for( ;; )
        {
            // Do other stuff
        }
    }).start();

    new Thread( () ->  // B
    {
        for( ;; )
        {
            synchronized( o ) {} // Refresh from main memory
            if( variable == 9 ) System.exit( 0 );
        }
    }).start();
}

final Object o = new Object();

如何在存储器模型的担保的能见度

两个线程必须同步上相同的对象,以便保证的可见性。这一保证在于 Java存储器模型, ,特别是在该规则,"解开行动监测m 进行同步-有 随后的所有锁行动对m"并由此 发生之前 这些行动。因此,一个是解锁的o显示在它的尾巴 synchronized 框发生之前B的后续锁定在其块。(注意,这是个奇怪的尾巴-头订的有关这就解释了为什么该机构可以是空的。) 给也一个人写信之前对其解和B的锁之前读的关系必须延伸到涵盖编写和阅读: 编写发生之前读.这是至关重要的,扩展关系,使经修订的程序正在存储器模型。

我认为这是最重要的使用对空 synchronized 块。


   * 我说的就好像是一个问题的处理缓存 因为我认为这是一个有用的方式观看。事实上,作为亚历山大*杜宾斯基发表了评论意见,所有现代的处理器是cache-连贯一致。这种情况发生之前的关系更多是关于什么的编译器是允许这样做,而不是CPU。'

它曾经是,说明书暗示某些存储器屏障操作发生的情况。然而,该规范已经改变,原来的规范从未正确实施。它可被用于等待另一个线程来解除锁定,但协调的是,其他线程已经获取锁定将是棘手的。

同步确一点点多只是等待,同时不优雅的编码这可能达到的效果所必需的。

http://www.javaperformancetuning.com/news/qotm030.shtml

  1. 在线取得该锁上的监视对象的这种(假设监测是解锁,否则线等待,直到的监测是解锁).
  2. 螺纹记忆冲其所有的变量,即它具有其所有的变量有效地读取从"主要的"存储器(Jvm可以使用肮脏组,以优化这个所以,只有"脏"变量的刷新,但这在概念上是相同的。见第17.9Java语言的规范)。
  3. 代码块执行(在这种情况下设置返回值以目前价值i3,这可能只是被重置的,从"主要的"存储器)。
  4. (任何更改变通常会现在可以写出来"主要"记忆,但是对于geti3()我们没有变化。)
  5. 线释放锁上的监视对象这一点。

对于在深入探讨Java的内存模型,看看从谷歌的系列的编程语言中的高级主题“这个视频: http://www.youtube.com/watch?v=1FX4zco0ziY

它给什么样的编译器可以(通常在理论上,但有时在实践中)做你的代码一个非常好的概述。基本的东西任何严重的Java程序员!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top