150

Java 文档说:

同一对象上的同步方法的两次调用不可能交错。

这对静态方法意味着什么?由于静态方法没有关联对象,同步关键字会锁定类而不是对象吗?

4

8 回答 8

202

只是为了给 Oscar 的答案(非常简洁!)添加一点细节,Java 语言规范的相关部分是8.4.3.6, 'synchronized Methods'

同步方法在执行之前获取监视器(第 17.1 节)。对于类(静态)方法,使用与方法类的 Class 对象关联的监视器。对于实例方法,使用与 this(调用该方法的对象)关联的监视器。

于 2009-01-13T02:58:41.817 回答
132

由于静态方法没有关联对象, 同步关键字会锁定类而不是对象吗?

是的。:)

于 2009-01-13T00:53:30.803 回答
81

您必须注意的一点(一些程序员通常落入那个陷阱)是同步的静态方法和同步的非静态方法之间没有联系,即:

class A {
    static synchronized f() {...}
    synchronized g() {...}
}

主要的:

A a = new A();

线程 1:

A.f();

线程 2:

a.g();

f() 和 g() 彼此不同步,因此可以完全同时执行。

于 2009-01-13T11:02:43.507 回答
15

除非您按如下方式实现 g():

g() {
    synchronized(getClass()) {
        ...
    }
}

当我想在对象的不同实例之间实现互斥(例如,在访问外部资源时需要)时,我发现这种模式也很有用。

于 2010-02-05T21:19:12.617 回答
4

查看有关 内在锁和同步的 oracle 文档页面

您可能想知道调用静态同步方法时会发生什么,因为静态方法与类相关联,而不是与对象相关联。在这种情况下,线程获取与类关联的类对象的内在锁因此,对类的静态字段的访问由不同于任何类实例的锁的锁控制

于 2016-11-01T08:06:38.407 回答
2

静态方法也有关联的对象。它属于 JDK 工具包中的 Class.class 文件。当 .class 文件加载到 ram 中时,Class.class 会创建它的一个实例,称为模板对象。

例如:-当您尝试从现有客户类创建对象时,例如

Customer c = new Customer();

Customer.class 加载到 RAM 中。在那一刻,JDK 工具包中的 Class.class 创建了一个名为 Template 对象的对象,并将该 Customer.class 加载到该模板对象中。该 Customer.class 的静态成员成为该模板对象中的属性和方法。

所以静态方法或属性也有对象

于 2016-11-09T04:55:00.217 回答
2

下面的例子更清楚地说明了类和对象锁,希望下面的例子也能帮助其他人:)

例如,我们有以下方法,一个是获取类,另一个是获取对象锁:

public class MultiThread {

    public static synchronized void staticLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }

    public synchronized void objLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

所以,现在我们可以有以下场景:

  1. 当使用相同对象的线程尝试同时访问objLock OR staticLock方法时(即两个线程都尝试访问相同的方法)

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
    
  2. 当使用相同对象的线程尝试同时访问staticLockobjLock方法时(尝试访问不同的方法)

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
    
  3. 当使用不同对象的线程尝试访问staticLock方法时

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
    
  4. 当使用不同对象的线程尝试访问objLock方法时

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
    
于 2017-08-13T04:45:57.457 回答
0

对于那些不熟悉锁定在类对象上的静态同步方法的人,例如对于字符串类它的 String.class,而实例同步方法锁定在 Java 中的“this”关键字表示的 Object 的当前实例上。由于这两个对象不同,它们具有不同的锁,因此当一个线程正在执行静态同步方法时,java中的其他线程不需要等待该线程返回,而是将获取表示为字节.class文字的单独锁并进入静态同步方法。

于 2017-05-24T02:50:44.523 回答