在Java中,静态同步方法的用途是什么?

90
我脑海中有一个问题。我读到过静态同步方法锁定类对象,而同步方法锁定当前对象实例。那么“锁定”类对象的意思是什么呢?
请问有人能帮我解答这个问题吗?

1
任何“同步”方法或块在进入时都会被“锁定”,以便一次只能有一个线程执行该方法/块(相对于锁定对象)。此外,一次只能有一个线程执行任何在同一对象上锁定的方法/块。静态同步方法在Class对象上被锁定。 - Hot Licks
2
@Zavior 我不认为这是重复的 - 你链接的问题是关于“如何完成”,而这个问题是关于“为什么要这样做”。 - Sergey Kalinichenko
1
@dasblinkenlight 我认为你是正确的。 - Zavior
7个回答

110
一般来说,synchronized方法用于保护被同时访问的资源。当被同时访问的资源属于类的每个实例时,您使用synchronized实例方法;当资源属于所有实例(即它是一个static变量)时,则使用synchronized static方法来访问它。
例如,您可以创建一个static工厂方法,该方法保留它所产生的所有对象的“注册表”。这样的注册表的自然位置将是一个static集合。如果您的工厂从多个线程中使用,则需要使工厂方法synchronized(或在方法内部具有synchronized块),以保护对共享static集合的访问。
请注意,在没有特定锁定对象的情况下使用synchronized通常不是构建供他人编写的代码库时最安全的选择。这是因为恶意代码可能会在您的对象或类上同步,以阻止执行您自己的方法。为了保护您的代码免受此类攻击,请创建一个私有“锁”对象,实例或静态,并在该对象上进行同步。

95

在运行时,每个加载的类都有一个Class对象实例。这个对象被用作static synchronized方法的共享锁对象。(任何同步方法或块都必须锁定某个共享对象。)

如果需要,您也可以手动同步此对象(无论是在静态方法中还是非静态方法中)。这三种方法的行为相同,只允许一个线程进入内部块:

class Foo {
    static synchronized void methodA() {
        // ...
    }

    static void methodB() {
        synchronized (Foo.class) {
            // ...
        }
    }

    static void methodC() {
        Object lock = Foo.class;
        synchronized (lock) {
            // ...
        }
    }
}
static synchronized 方法的意图是当您想要允许仅有一个线程同时使用存储在类的 static 变量中的某些可变状态时使用。
如今,Java 已经拥有了更加强大的并发特性,在 java.util.concurrent 及其子包中,但是核心的 Java 1.0 结构,例如 synchronized 方法仍然是有效且可用的。

9
感谢您的夸奖。在阅读您的答案之前,我对这个话题并不清楚。即使是Java文档也没有像您一样清晰地解释。致敬! (原文中有些口语化表达,已做适当调整以符合书面语规范) - Vicky Thakor
在一个static方法中只使用synchronized { ... }代码块(即没有显式指定锁对象),是否等价于并假定要使用的锁对象是类本身? - Adam Burley
2
@AdamBurley 没有这样的语法。它无法编译。 - Boann

73
简言之,一个 static synchronized 方法会锁定整个类而不是对象,并且它会锁定类,因为关键字 static 的意思是:"类而不是实例"。
关键字 synchronized 表示一次只有一个线程可以访问该方法。
static synchronized 意味着:

一次只有一个线程可以访问该类。


3
另请参阅更多详细信息 - http://www.javatpoint.com/static-synchronization-example - amar
5
best one in just 4 lines :) - roottraveller

13
假设一个类中有多个静态同步方法(m1,m2,m3,m4),并且假设一个线程正在访问m1,则同时没有其他线程可以访问任何其他静态同步方法。

静态变量怎么样? - marcolopes

1

静态方法可以被同步。但每个类只有一个锁。当Java类被加载时,相应的java.lang.class类对象存在。这个对象的锁需要用于静态同步方法。因此,如果您有一个静态字段应该被限制为一次由多个线程访问,您可以将这些字段设置为私有,并创建公共的静态同步setter或getter来访问这些字段。


0
Java虚拟机(VM)每个类都包含一个类对象。每个类可能有一些共享变量,称为静态变量。如果代码的关键部分在并发环境中使用这些变量,则需要将该特定部分设置为同步。当存在多个静态同步方法时,只有其中一个方法会在没有抢占的情况下执行。这就是类对象锁的作用。

0
我觉得你已经从上面得到了答案,但为了确保我的知识,我会解释一下问题,请帮我指出答案中的错误或不足之处,谢谢!
我相信这里是一个实例,即“同步方法锁定当前对象的实例”。
//Your object

class Y {

//Method

 void method(){

//No need synchronized lines of code

  synchronized (this) {

/* The lines of code *instance of an object* runing concurrently 
without the outer block of code */

/* Synchronized method will execute only one current at a time if
it (the instance of the object) is concurrent and lock every other current */

  }

//No need synchronized lines of code

 }
}

所以,在我看来,在静态同步方法中锁定类对象的意义与同步方法完全相同,只是规模更大(类对象)!

这篇帖子被放在了回答部分,但听起来更像是一个问题。您能确认一下这是否是一个回答吗? - halfer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接