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

Java 文档说:

控件上的两个同步方法调用是不可能的 相同的物体交错。

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

100775 次浏览

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

是的

只是为了给奥斯卡增加一点细节(简洁得令人愉快!)答案是,有关 Java 语言规格的章节是 8.4.3.6,「同步方法」:

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

有一点你必须小心(一些程序员通常会掉进这个陷阱) ,那就是在同步的静态方法和同步的非静态方法之间没有联系,例如:

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

主要内容:

A a = new A();

线程1:

A.f();

线程2:

a.g();

F ()和 g ()不是彼此同步的,因此可以完全并发地执行。

除非像下面这样实现 g () :

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

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

看一下关于 内部锁和同步的 Oracle 文档页面

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

静态方法还有一个相关联的对象。它属于 JDK 工具箱中的 Class.class 文件。当。类文件加载到内存中,Class.class 会创建一个名为 template object 的实例。

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

Customer c = new Customer();

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

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

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

下面的例子给出了类和对象锁之间更清晰的区别,希望下面的例子也能帮到其他人:)

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

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 或者 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. When threads using same Object tries to access staticLock and objLock methods same time (tries accessing different methods)

    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. When threads using different Object tries to access staticLock method

    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. When threads using different Object tries to access objLock method

    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