同步(this)阻止整个对象? [复制]

Posted

技术标签:

【中文标题】同步(this)阻止整个对象? [复制]【英文标题】:synchronized(this) blocks whole object? [duplicate] 【发布时间】:2012-08-12 10:51:06 【问题描述】:

可能重复:synchronized block vs synchronized method?

从这个问题的接受答案:In Java critical sections, what should I synchronize on? 我知道了

public synchronized void foo() 
    // do something thread-safe

和:

public void foo() 
    synchronized (this) 
        // do something thread-safe
    

做同样的事情。但是在第一种情况下,我们只使对象的一个​​方法同步,而在第二种情况下,我们使整个对象无法访问。那么为什么这两个代码片段做同样的事情呢?

【问题讨论】:

***.com/questions/1149928/… , ,***.com/questions/10185867/… , ***.com/questions/8519700/… 【参考方案1】:

你似乎在混合东西。

首先

public synchronized void method() 

从同步的角度来看,等同于:

public void method() 
    synchronized (this) 
    

已经提到了优点/缺点,并且各种重复提供了更多信息。

其次,

synchronized(someObject) 
    //some instructions

表示同步块中的指令不能被2个线程同时执行,因为它们需要获取someObject上的监视器才能这样做。 (假设 someObject 是一个不会改变的最终引用)。

在您的情况下,someObject 恰好是 this

对象中任何未同步的代码仍然可以并发执行,即使this 上的监视器因为正在运行同步块而被线程持有。换句话说,synchronized(this) 不会“锁定整个对象”。它只防止 2 个线程同时执行同步块。

最后,如果您有两个synchronized 方法(都使用this 作为锁),如果一个线程(T1)获得this 上的锁以执行这两个方法之一,则不允许其他线程执行这两种方法中的任何,因为它们需要获取this 上的锁,该锁已由 T1 持有。

这种情况可能会在关键部分产生争用,在这种情况下,必须使用更细粒度的锁定策略(例如,使用多个锁定)。

【讨论】:

谢谢,你解释了我不明白的一切。但我不明白为什么我需要锁定最终(不可更改)对象?:That assumes that someObject is a final reference that does not change。什么是监视器?物理意义是什么?在Object 类的源代码中,我没有找到任何与监视器相关的信息。这是一些标志,如Boolean?再次感谢。 问题太多了! (1) final:如果你使用synchronized(someObjectThatIsNotFinal),并且在你的代码中的某个地方,你有someObjectThatIsNotFinal = new Object();,下一个线程将锁定一个不同的对象,并且可以进入同步块,而另一个线程仍然在那里。 (2)monitors are defined in the JLS。它是如何实现的取决于 JVM,Object 类本身没有任何东西指向监视器。 非常感谢您,很好的解释:)【参考方案2】:

我们不同步一个对象,而是同步一个代码块。第一个代码块是方法本身,而第二个是synchronized 块。

该对象只提供锁以防止多个线程同时进入该代码块。在第一种情况下,this 对象(调用该方法的对象)将被隐式用作锁,而在第二种情况下,它并不总是必须是 this 对象,它可能是一些其他对象也是。

【讨论】:

好吧,我想当使用this作为参数时,我们锁定了WHOOLE对象。但是现在又出现了另一个问题...synchronized (this) 意味着Thread1 可以获取对象的监视器,所以Thread2 无法访问临界区,直到Thread1 释放它。但是,如果我们在类中有几个关键部分,我们将this 作为参数传递(我认为每个对象只有一个监视器,没有更多)?例如 Thread1 进入临界区并获取对象的监视器,同时 Thread2 想要执行 另一个 临界区,但它看到对象的 (this) 监视器没有释放。 @MyTitle 评论有点太长了 - 请参阅我的回答。【参考方案3】:

他们做同样的事情。第一种形式是第二种形式的简写。

这两个结构之间的一个小区别是 - 同步块被编译成monitorenter(操作码0xC2)和monitorexit(操作码0xC3)指令。 编译时,同步方法在运行时常量池中的区别在于 ACC_SYNCHRONIZED 标志,由 JVM 的方法调用指令检查。但是,这种差异在实践中并没有太大意义。

【讨论】:

【参考方案4】:

他们不做同样的事情。第一部分从头到尾同步。其次只是同步块(不是整个方法)。第二个有一定的灵活性。

【讨论】:

但在这种情况下,同步块覆盖了 整个 方法..(或整个“做某事”部分)。 嗯。但是我们说我们想要锁定整个对象,直到关键代码没有执行,因为我们作为参数 this 对象传递。所以我认为在同步块中使用this 时,我们会锁定所有对象。但是当我们使用私有引用而不是this 时,我们只锁定同步块..

以上是关于同步(this)阻止整个对象? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

对象复制问题

假设我不使用任何重载函数,有没有办法可以阻止所有名称修改? [复制]

如何屏蔽用户? [复制]

阻止异步提取在webpacked应用程序中完成

如何阻止核心数据同步到 iCloud

Pubnub 阻止排毒同步