在您的示例中,该方法 同时 锁定了
Foo和的实例
bar。其他方法可能仅锁定对象的实例
Foo或 对象
bar。
因此,是的,这完全取决于他们在做什么。大概
bar可以保护一些较小的数据子集,并且某些方法只需要锁定就
bar可以以线程安全的方式执行其操作。
是什么synchronized
呢
synchronized(在方法上或在语句中)创建互斥区(
关键部分, 或者对于Java特别是
可重入互斥体
)。线程进入关键部分的“关键”是
synchronized语句‡中使用的对象引用。在使用同一密钥的所有块中,一次只能有一个线程(递归)“拥有”该“密钥”;也就是说,一次只能有一个线程可以输入
synchronized给定对象引用上的任何块。
这样的关键部分只是防止您在块内执行的 操作
(变量读/写)与锁定同一对象引用的所有其他关键部分中的任何其他操作同时发生。(它不会自动保护对象内的所有变量)。
在Java中,这样的关键部分还会
在 合同
之前 创建一个
偶然事件 。
举个例子
作为一个人为的例子†:
public class Foo { final Bar bar = new Bar(); private int instanceCounter = 0; private int barCounter = 0; public synchronized void incrementBarCounterIfAllowed() { synchronized (bar) { if (instanceCounter < 10) barCounter++; } } public synchronized void incrementClassCounter() { instanceCounter++; } public void incrementBarCounter() { synchronized (bar) { barCounter++; } }}实例变量是否是私有的与这种方法是否适用无关紧要。在单个类中,您可以有多个锁对象,每个锁对象都保护自己的数据集。
但是这样做的风险是,你必须是 非常 严格的编码规范,以防止死锁通过在不同的地方不同的顺序锁两把锁。例如,使用上面的代码,然后从代码中的其他位置进行操作:
synchronized(myFoo.bar) { myFoo.incrementClassCounter();}您可能会为此
incrementBarCounterIfAllowed()方法陷入僵局
† 请注意,这barCounter
可能是Bar
etc等的实例变量-为了简洁起见,我避免了这样做。
‡对于
synchronized方法,该引用是对类实例的引用(或
Class<?>对
static方法的类的引用)。



