首页>Program>source

我正在查看有关我的代码库的Findbugs报告,并且触发的模式之一是针对 空的维兹威兹 街区(即 synchronzied ).文档说

synchronized (var) {}

在我的情况下,发生的原因是该块的内容已被注释掉,但是 声明仍然在那里.在什么情况下可能会出现空的

Empty synchronized blocks are far more subtle and hard to use correctly than most people recognize, and empty synchronized blocks are almost never a better solution than less contrived solutions.

synchronized
最新回答
  • 2天前
    1 #

    一个空的同步块将等待,直到没有其他人正在使用该同步器.那可能就是您想要的,但是因为您没有保护同步块中的后续代码,所以没有什么可以阻止其他人修改在运行后续代码时正在等待的内容.

  • 2天前
    2 #

    先前的答案未能强调空 synchronized最有用的内容 块:它们可以确保跨线程的变量更改和其他操作的可见性.正如jtahlborn所指出的,同步对编译器施加了"内存屏障",迫使其刷新和刷新其缓存.但是我没有找到" SnakE讨论"的地方,所以我自己写了一个答案。

    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可能永远不会读取A写入的值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上的所有后续锁定动作同步,从而先发生这些动作.因此,A在其 synchronized尾部解锁了o的监视器 块发生-在B随后锁定在其块的开头之前. (请注意,正是这种关系的奇怪的尾部顺序解释了主体为何可以为空的原因。)还要考虑到A的写操作先于其解锁,B的锁操作先于其读取,该关系必须扩展为覆盖write和read: em>在写入之前发生写操作.正是这种至关重要的扩展关系使修订后的程序在内存模型方面正确无误。

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


    *我说的好像是处理器缓存有关 因为我认为这是一种有用的查看方式。 实际上,正如亚历山大·杜宾斯基(Aleksandr Dubinsky)所说,‘所有现代处理器都是缓存一致的。 先发生后发生的关系更多的是允许编译器执行操作,而不是CPU。’

  • 2天前
    3 #

    过去,在规范中隐含了发生某些内存屏障操作的情况.但是,该规范现已更改,并且原始规范从未得到正确实施.它可能用于等待另一个线程释放锁,但是要协调另一个线程已经获取了锁将很棘手。

  • 2天前
    4 #

    同步的作用不只是等待,还有编码不足的问题.这样可以达到所需的效果.

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

      The thread acquires the lock on the monitor for object this (assuming the monitor is unlocked, otherwise the thread waits until the monitor is unlocked).

      The thread memory flushes all its variables, i.e. it has all of its variables effectively read from "main" memory (JVMs can use dirty sets to optimize this so that only "dirty" variables are flushed, but conceptually this is the same. See section 17.9 of the Java language specification).

      The code block is executed (in this case setting the return value to the current value of i3, which may have just been reset from "main" memory).

      (Any changes to variables would normally now be written out to "main" memory, but for geti3() we have no changes.)

      The thread releases the lock on the monitor for object this.

    p

    要深入了解Java的内存模型,请观看Google的"编程语言高级主题"系列中的以下视频: http://www.youtube.com/watch?v=1FX4zco0ziy

    它很好地概述了编译器可以对代码执行的功能(通常在理论上,但有时在实践中).对于任何认真的Java程序员来说都是必不可少的东西!

  • 带有事件对象的Python线程
  • datagrid:wpf-当属性更改而不考虑新值时触发datatrigger