如果methodA和methodB使用不同的数据结构,并且在其他人调用methodB时调用methodA是安全的,那么这两个方法应该使用不同的锁。
这里是synchronized(XYZ.class)的瘦身
synchronized (XYZ.class) 是您实现上述模式的方式——它是一个同步块:
- 获取对象上的锁(在此类中是代表 XYZ 的 java.lang.class 的实例)
- 做了一些工作
- 释放锁。
关键是要记住,Java 中的每个对象都有一个锁(技术术语是监视器),一次只能由一个线程持有。您可以为您引用的任何对象请求锁定。
方法上的同步关键字:
public synchronized void foo() {
//do something
}
只是语法糖:
public void foo() {
synchronized(this) {
//do something
}
}
这种方法有一个明显的缺点:由于任何人都可以获取对象的锁,因此如果外部调用者获取并持有对象锁,同步方法将无法正常工作。
(顺便说一句,这就是为什么锁定 XYZ.class 也是一个坏主意:它是一个全局可访问的对象,你永远不知道谁可能决定获取它的锁)
为了避免这些缺点,通常使用这种模式来代替同步方法:
private final Object LOCK = new Object();
public void foo() {
synchronized(LOCK) {
//do something
}
}
由于没有外部调用者可以引用 LOCK 对象,因此只有这个类可以获取它的锁,并且同步方法将始终按预期工作。
当您有两个不同的方法需要分别锁定时,通常的做法是让每个方法锁定一个不同的私有对象:
private final Object LOCKA = new Object();
private final Object LOCKB = new Object();
public void foo() {
synchronized(LOCKA) {
//do something
}
}
public void bar() {
synchronized(LOCKB) {
//do something else
}
}
那么有可能一个线程调用 foo() 而另一个线程正在调用 bar(),但是一次只能有一个线程可以调用 foo(),并且只有一个线程可以调用 bar( ) 一次。