有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

在JAVA中,多线程可以有多个线程执行静态同步方法

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

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) 个答案

  1. # 1 楼答案

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

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

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

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

    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的实例,否则无法使用它。但事实并非如此。您只能从同一个类的主体中使用它,但仍然可以在中编写一个静态方法,该方法将能够创建两个线程(例如,扩展Thread的静态嵌套类),并且这两个线程将运行A.m1(),而不会创建A的单个实例

    这就是为什么我们坚持认为该规则适用于线程,而不适用于A实例。线程的数量与实例的数量无关


    至于类对象:类对象(如A.class)属于^{}类型,在Java中用于从一个级别上表示类及其功能。您可以使用它来创建类的实例,而无需使用new这个词、调用它的方法以及其他许多用途

    所以,A有这样一个类对象,这个对象是用来保存静态方法监视器的对象。类对象是在加载该类时创建的。而类通常在程序需要时加载

    但在某些情况下,如果一个程序中有多个类装入器,理论上可能会发生这种情况,两个以上的人加载了A.class文件(或者从网上下载,或者从其他来源获得,这都无关紧要——只是他们都使用了相同的字节码,具有相同的名称和包,并加载了它)

    在这种情况下,您可能有两个同名的类,但Java并不认为它们是同一个类。如果你得到一个实例(相当于new A()),然后是另一个实例,这或多或少会像是有两个不同的类使用相同的代码。在这种情况下,因为就Java而言,尽管它们具有相同的名称,但它们不是同一个类,那么您可以让一个线程运行“a#1”的方法m1,让一个线程运行“a#2”的方法m1,并且它们可以同时执行

  2. # 2 楼答案

    As far as I understand it, this ensures that only one of all the existent class instances will be allowed to execute the static synchronized method.

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

    正如它在the specification中所说:

    A synchronized method acquires a monitor (§17.1) before it executes.

    For a class (static) method, the monitor associated with the Class object for the method's class is used.


    Can there be 2 class instances executing the static synchronized method concurrently, or not?

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

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