【问题标题】:Scope of synchronization on .class objects in the JVMJVM 中 .class 对象的同步范围
【发布时间】:2015-02-22 15:05:46
【问题描述】:

假设我有以下代码:

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

【问题讨论】:

  • 嗯,JVM 是一个进程,那么您的第一个问题是什么意思?
  • @fge 我想这个问题可能适用于多个网络应用程序。
  • @fge 我猜你是对的,我没想到这个。
  • @BoristheSpider.. 我不明白你的意思。每个 Web 应用程序在容器(比如 tomcat)中都有一个不同的类加载器,所以即使 Test.class 在共享库中,当它实际加载时,它们都会创建一个该类加载器唯一的 Test.class 实例,并且用作锁。我在这里错过了什么吗?
  • @AniketThakur 它,例如 - here's the Tomcat documentation.

标签: java class jvm synchronization locking


【解决方案1】:

当您有多个 ClassLoader 时,每个 ClassLoader 都可以拥有自己的类实例(或共享一个类的实例),例如String.class 将被共享,但 MyType.class 在每个“应用程序”中可能会有所不同,前提是每个应用程序都有自己的类加载器。

在锁定方面,Class 对象并没有什么特别之处,只是它在 static synchronised 方法中隐式使用。

例如

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

差不多
class MyType {
    static void method() { 
        synchronized(MyType.class) {
        }
    }
}

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

      synchronize (Test.class) {
         ...
      }
      

      锁是通过 Test.class 对象获得的。同样对于完全限定的类名,JVM 将确保每个类加载器只加载一次(除非它是 GCed)。因此,每个 JVM 实例始终只有一个 Test.class 实例(考虑到类加载是由加载的同一个类完成的)。 JVM实例是指一个拥有自己PID的Java进程。如果一个线程对Test.class 有锁,除非它被持有线程释放,否则没有其他线程可以获得这个锁(同一个线程可以再次获得锁——Java 中的锁是可重入的)。

      如果你启动一个新的java进程->新的JVM实例->Test.class的新实例被类加载器加载->它的锁可以被获取,并且不依赖于任何其他运行的JVM实例。

      注意:如果 Class 对象是分开的(例如,同一个类由不同的类加载器加载 - 就像在 web 应用程序中发生的情况一样),那么您当然可以分别获得每个对象的锁定。您将无法将一个类的实例转换为另一个类。

      【讨论】:

      • 这不是真的 - 所以你将永远只有一个Test.class的实例。如果您有任何自定义 ClassLoader 行为,则不会,当然也不会在 Web 应用程序中。
      • @BoristheSpider 是的,我的意思是每个类加载器一个。至于网络应用程序被认为是每个网络应用程序中的类(/WEB-INF/classes/WEB-INF/lib/*.jar)由不同的类加载器加载,并且将表现得像不同的类,包括锁定机制。
      • 所以更正你的答案,或者继续收集反对票。目前完全不正确。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-25
      • 1970-01-01
      • 1970-01-01
      • 2012-08-31
      • 2013-02-17
      相关资源
      最近更新 更多