同步(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)阻止整个对象? [复制]的主要内容,如果未能解决你的问题,请参考以下文章