从接受的答案回答这个问题: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
}
}
做同样的事情。但是在第一种情况下,我们只对一个对象的方法进行同步,而在第二种情况下,我们使得不可访问的整个对象。那么为什么这两个代码片段会做同样的事情呢?
答案 0 :(得分:5)
你似乎在混合东西。
首先
public synchronized void method() {
}
从同步的角度来看,等同于:
public void method() {
synchronized (this) {
}
}
已经提到了优点/缺点,各种副本提供了更多信息。
其次,
synchronized(someObject) {
//some instructions
}
表示同步块中的指令不能由2个线程同时执行,因为它们需要在someObject
上获取监视器才能执行此操作。 (这假设someObject是一个不会改变的最终引用。)
在您的情况下,someObject
恰好是this
。
对象中未同步的任何代码仍然可以同时执行,即使this
上的监视器由一个线程持有,因为它正在运行synchronized块。换句话说,synchronized(this)
不会“锁定整个对象”。它只能防止2个线程同时执行同步块。
最后,如果你有两个synchronized
方法(都使用this
作为锁),如果一个线程(T1)获取this
上的锁来执行这两个方法之一,不允许其他线程执行这两种方法中的任何,因为它们需要获取this
上已锁定的锁。
这种情况可能会在关键部分产生争用,在这种情况下,必须使用更精细的锁定策略(例如,使用多个锁)。
答案 1 :(得分:1)
我们不同步对象,而是同步一段代码。在第一个代码块是方法本身,而在第二个代码块是synchronized
块。
该对象仅提供锁定,以防止多个线程同时进入该代码块。在第一种情况下,this
对象(调用该方法的对象)将隐式用作锁,而在第二种情况下,它不一定必须是this
对象,它也可能是其他一些对象。
答案 2 :(得分:1)
他们做同样的事情。第一种形式是第二种形式的简写。
这两个结构之间的一个细微差别是 - 同步块被编译为monitorenter
(操作码0xC2
)和monitorexit
(操作码0xC3
)指令。
编译时,synchronized方法在运行时常量池中区分
ACC_SYNCHRONIZED
标志,由JVM检查方法调用指令。然而,这种差异在实践中没有多大意义。
答案 3 :(得分:0)
他们不做同样的事情。第一部分从头到尾同步。第二个是同步块(不是整个方法)。第二个有一些灵活性。