在示例方法中,方法 A 和方法 B 是实例方法(与静态方法相反)。放置实例方法意味着线程必须先获取调用该方法的对象实例上的锁(“内部锁”),然后线程才能开始执行该方法中的任何代码。synchronized
如果您有两个不同的实例方法标记为已同步,并且不同的线程在同一对象上并发调用这些方法,则这些线程将争用相同的锁。一旦一个线程获得锁定,所有其他线程都将从该对象上的所有同步实例方法中关闭。
为了使这两种方法同时运行,它们必须使用不同的锁,如下所示:
class A {
private final Object lockA = new Object();
private final Object lockB = new Object();
public void methodA() {
synchronized(lockA) {
//method A
}
}
public void methodB() {
synchronized(lockB) {
//method B
}
}
}
其中,同步块语法允许指定执行线程需要获取内部锁才能进入块的特定对象。
需要了解的重要一点是,即使我们在各个方法上放置了一个“同步”关键字,核心概念也是幕后的内在锁。
以下是 Java 教程描述这种关系的方式:
同步是围绕称为内部锁或监视器锁的内部实体构建的。(API 规范通常将此实体简称为“监视器”。固有锁在同步的两个方面都发挥着作用:强制对对象状态的独占访问,并建立对可见性至关重要的发生前关系。
每个对象都有一个与之关联的固有锁。按照惯例,需要对对象字段进行独占和一致访问的线程必须在访问对象的字段之前获取对象的固有锁,然后在完成它们时释放固有锁。据说线程在获取锁和释放锁之间拥有固有锁。只要一个线程拥有固有锁,就没有其他线程可以获得相同的锁。另一个线程在尝试获取锁时将阻塞。
锁定的目的是保护共享数据。仅当每个锁保护不同的数据成员时,才使用上述示例代码中所示的单独锁。