在JAVA中是否可以有1个以上的线程执行静态同步方法

在JAVA中是否可以有1个以上的线程执行静态同步方法,java,multithreading,Java,Multithreading,我一直在网上寻找关于如何执行静态同步方法的信息。我发现静态同步方法将获取类锁。据我所知,这确保了所有现有类实例中只有一个被允许执行静态同步方法。真的是这样吗?是否有2个类实例同时执行静态同步方法?所以,为了让它更直观,我添加了一个代码示例 public class A { private static synchronized void m1() { //Print something } private synchronized void m2() {

我一直在网上寻找关于如何执行静态同步方法的信息。我发现静态同步方法将获取类锁。据我所知,这确保了所有现有类实例中只有一个被允许执行静态同步方法。真的是这样吗?是否有2个类实例同时执行静态同步方法?所以,为了让它更直观,我添加了一个代码示例

public class A {

   private static synchronized void m1() {
      //Print something
   }

   private synchronized void m2() {
      //Print something else
   }
}
我理解,因为静态方法获取类级监视器,而非静态方法获取对象级监视器,所以两者可以从两个不同的线程同时执行,如下所示:

A a = new A;
a.m2();//object-level lock acquired
a.m1();//Class-level lock acquired
但是,如果我们有上述类的3个实例,它们是否都可以并发运行m1()?我想他们不能,但我不确定。那么这会发生吗

A a = new A;
A aa = new A;
A aaa = new A;

a.m1();
aa.m1();
aaa.m1();
据我所知,这确保了所有现有类实例中只有一个被允许执行静态同步方法

不,这意味着一个线程将能够执行该方法,并且同步锁是特定类加载器中的类对象

正如书中所说:

同步方法在执行之前获取监视器(§)

对于类(静态)方法,将使用与该方法的类的类对象关联的监视器


是否有2个类实例同时执行静态同步方法

“类实例”是一个模糊的术语。如果你指的是一个类的实例,那是不相关的;这是一个
静态的
(类范围)方法,而不是实例方法。如果您指的是类对象,那么这就是我在上面提到类加载器的原因:在有多个类加载器的异常情况下,您可以有多个类对象-例如,类的副本(不是它的实例)。如果有多个类对象,则每个类对象都有自己的
静态
方法副本。因此,由于在不同的对象上同步了两个副本,一个线程可以调用其中一个对象的
synchronized
static
方法,而另一个线程则调用其中一个对象的
synchronized
static
成员

但这是一个边缘案例。在正常情况下,这不是问题:您只有方法的一个副本,它在类对象的一个副本上同步,并且在任何给定时间只有一个线程可以执行它

据我所知,这确保了所有现有类实例中只有一个被允许执行静态同步方法

不,这意味着一个线程将能够执行该方法,并且同步锁是特定类加载器中的类对象

正如书中所说:

同步方法在执行之前获取监视器(§)

对于类(静态)方法,将使用与该方法的类的类对象关联的监视器


是否有2个类实例同时执行静态同步方法

“类实例”是一个模糊的术语。如果你指的是一个类的实例,那是不相关的;这是一个
静态的
(类范围)方法,而不是实例方法。如果您指的是类对象,那么这就是我在上面提到类加载器的原因:在有多个类加载器的异常情况下,您可以有多个类对象-例如,类的副本(不是它的实例)。如果有多个类对象,则每个类对象都有自己的
静态
方法副本。因此,由于在不同的对象上同步了两个副本,一个线程可以调用其中一个对象的
synchronized
static
方法,而另一个线程则调用其中一个对象的
synchronized
static
成员


但这是一个边缘案例。在正常情况下,这不是问题:您只有方法的一个副本,并且它在类对象的一个副本上同步,并且在任何给定的时间只有一个线程可以执行它。

除了另一个答案之外,还需要进一步澄清:

通常,没有两个线程可以访问在类监视器上同步的静态方法

但这与类本身的实例无关。为了让线程运行该静态方法,不需要类的实例。该方法是静态的,因此即使没有类的实例也可以使用。也就是说,内存中不存在
A
,但是您可以访问它的方法

例如,如果您的方法是public,则可以执行以下操作:

public class Test extends Thread {
    @Override
    public void run() {
        A.m1();
    }

    public static void main( String args[] ) {
       Test thread1 = new Test();
       Test thread2 = new Test();

       thread1.start();
       thread2.start();
    }
}
运行这个
Test
类,您将有两个线程,它们将调用
A.m1()
,并且由于它在类监视器上是同步的,因此它们将无法在同一时间执行。但这里的要点是,内存中甚至没有一个
a
类型的对象。它们直接使用静态方法,而不创建实例。不需要
A
的实例来运行
A.m1()
方法

现在,您将您的方法设置为私有。因此,您可能认为除非有
A
的实例,否则无法使用它。但事实并非如此。您只能从同一类的主体中使用它,但仍然可以在中编写一个static方法,该方法将能够创建两个线程(例如,扩展
线程的静态嵌套类
),并且这两个线程将运行
a.m1()
,而不创建
a
的单个实例

这就是为什么我们坚持该规则适用于线程,而不是