在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();
# 1 楼答案
除了另一个答案之外,还需要进一步澄清:
通常,没有两个线程可以访问在类监视器上同步的静态方法
但这与类本身的实例无关。为了让线程运行该静态方法,不需要类的实例。该方法是静态的,因此即使没有该类的实例,它也是可用的。也就是说,内存中不存在
A
,但是您可以访问它的方法例如,如果您的方法是公共的,您可以执行以下操作:
运行这个
Test
类,你会有两个线程,它们会调用A.m1()
,因为它在类监视器上是同步的,所以它们不能同时执行。但这里的重点是,内存中甚至没有一个A
类型的对象。它们直接使用静态方法,而不创建实例。不需要A
的实例来运行A.m1()
方法现在,你把你的方法保密了。因此,您可能会认为,除非有
A
的实例,否则无法使用它。但事实并非如此。您只能从同一个类的主体中使用它,但仍然可以在中编写一个静态方法,该方法将能够创建两个线程(例如,扩展Thread
的静态嵌套类),并且这两个线程将运行A.m1()
,而不会创建A
的单个实例这就是为什么我们坚持认为该规则适用于线程,而不适用于
A
的实例。线程的数量与实例的数量无关至于类对象:类对象(如} 类型,在Java中用于从一个级别上表示类及其功能。您可以使用它来创建类的实例,而无需使用
A.class
)属于^{new
这个词、调用它的方法以及其他许多用途所以,
A
有这样一个类对象,这个对象是用来保存静态方法监视器的对象。类对象是在加载该类时创建的。而类通常在程序需要时加载但在某些情况下,如果一个程序中有多个类装入器,理论上可能会发生这种情况,两个以上的人加载了
A.class
文件(或者从网上下载,或者从其他来源获得,这都无关紧要——只是他们都使用了相同的字节码,具有相同的名称和包,并加载了它)在这种情况下,您可能有两个同名的类,但Java并不认为它们是同一个类。如果你得到一个实例(相当于
new A()
),然后是另一个实例,这或多或少会像是有两个不同的类使用相同的代码。在这种情况下,因为就Java而言,尽管它们具有相同的名称,但它们不是同一个类,那么您可以让一个线程运行“a#1”的方法m1
,让一个线程运行“a#2”的方法m1
,并且它们可以同时执行# 2 楼答案
不,这意味着一个线程将能够执行该方法,并且同步锁是特定类加载器中的类对象
正如它在the specification中所说:
“类实例”是一个模糊的术语。如果你指的是一个类的实例,那就无关紧要了;这是一个}方法,而另一个线程则调用其中一个对象的}成员
static
(类范围)方法,而不是实例方法。如果你指的是类对象,那就是我在上面提到类加载器的原因:在不寻常的情况下,如果你有多个类加载器,你可以有多个类对象——例如,类的副本(而不是类的实例)。如果有多个类对象,那么每个类对象都有自己的static
方法副本。因此,由于在不同的对象上同步了两个副本,一个线程可以调用其中一个对象的synchronized
{synchronized
{但这是一个边缘案例。在正常情况下,这不是问题:您只有一个方法副本,它在类对象的一个副本上同步,并且在任何给定的时间只有一个线程可以执行它