Java同步静态方法:锁定对象或类

时间:2009-01-13 00:48:39

标签: java class static methods synchronized

Java教程说:“同一个对象上的两个同步方法的调用不可能交错。”

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

8 个答案:

答案 0 :(得分:197)

只是为奥斯卡(令人愉悦的简洁!)答案添加一些细节,Java语言规范的相关部分是8.4.3.6, 'synchronized Methods'

  

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

答案 1 :(得分:125)

  

由于静态方法没有关联对象,是否会对类中的synchronized关键字进行锁定而不是对象?

是。 :)

答案 2 :(得分:79)

你需要注意的一点(一些程序员通常属于那个陷阱)是同步静态方法和同步非静态方法之间没有联系,即:

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

主:

A a = new A();

主题1:

A.f();

主题2:

a.g();

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

答案 3 :(得分:13)

除非你按如下方式实施g():

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

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

答案 4 :(得分:4)

查看Intrinsic Locks and Synchronization

上的oracle文档页面
  

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

答案 5 :(得分:2)

静态方法也有一个关联的对象。它属于JDK toolkit中的Class.class文件。当.class文件加载到ram中时,Class.class创建一个名为template object的实例。

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

Customer c = new Customer();

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

因此静态方法或属性也有一个对象

答案 6 :(得分: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
    

答案 7 :(得分:0)

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