JVM 中 .class 个对象的同步范围

Scope of synchronization on .class objects in the JVM

假设我有以下代码:

synchronize (Test.class) {
   ...
}
  1. 这是否意味着每个 Test.class 对象都被锁定 同一虚拟机中的其他程序 运行?或者这样做 锁只影响 JVM 中的这一个程序?
  2. 如果它影响每个程序:当 Test.class 处于两个程序通过不同但内容相同的 JAR 包含的依赖项时,锁是否仍会影响两个程序?

Java 是一种 OO 语言,这意味着您拥有对象,它们相互交互以形成一个完整的程序。每个对象都与一个监视器相关联。同步基本上是在对象监视器上实际获得锁定的对象上完成的。

现在回答你的问题。当你说

synchronize (Test.class) {
   ...
}

锁是在 Test.class 对象上获得的。此外,对于完全限定的 class 名称,JVM 将确保每个 class 加载程序只加载一次(除非它是 GCed)。因此,每个 JVM 实例始终只有一个 Test.class 实例(考虑到 class 加载是由相同的 class 加载完成的)。我所说的 JVM 实例是指 Java 进程,它将拥有自己的 PID。如果一个线程锁定 Test.class 除非它被持有线程释放,否则其他线程无法获得此锁(同一线程可以再次获得锁 - Java 中的锁是可重入性质的)。

如果你启动新的java进程 -> 新的JVM实例 -> Test.class的新实例被class加载器加载 -> 它的锁可以获得并且不依赖在任何其他 JVM 实例上 运行.

注意 :如果 Class 对象是分开的(例如,相同的 class 由不同的 class 加载程序加载 - 就像万一发生的情况网络应用程序)那么你当然可以在每个应用程序上单独锁定。您将无法将一个 class 的实例转换为另一个

你的 "programs" 只是你多次 运行 的不同 ClassLoader.load(programClass).main(args)。当然,它们共享一个类加载器、一台机器并且实际上是同一程序的不同部分,一个 OS 进程。只是调用各种 类 programs 没有任何改变。他们仍然彼此可见。如果一个人可以执行另一个人的方法,他们可以互相阻塞。

当您有多个类加载器时,每个类加载器都可以拥有自己的 class 实例(或共享 class 的实例),例如String.class 将被共享,但 MyType.class 可能在每个 "Application" 中不同,假设每个应用程序都有自己的 class 加载程序。

在锁定方面,Class 对象除了在 static synchronised 方法中隐式使用外,没有什么特别之处。

例如

class MyType {
    static synchronized void method() { }
}

大同小异
class MyType {
    static void method() { 
        synchronized(MyType.class) {
        }
    }
}

它执行相同的功能,尽管字节码不相同。