java中如何实现类级锁定?

sha*_*ome 2 java multithreading synchronization locks

我知道通过同步静态和非静态方法来分别锁定类和实例的锁定概念。我无法理解的是,类级锁是如何实现的?我的意思是,类只是一个模板,没有物理意义。那么,当我们说通过同步静态方法实现类级锁定时,会发生什么?该类的所有对象是否都被锁定或其他一些进程?

通过我的搜索,我发现有类对象(Class.class)并且在这个类对象上获取了锁。但是,该类的所有实例又是如何被锁定的呢?

Sol*_*low 5

该类的所有对象是否都被锁定或其他一些进程?

首先,让我们谈谈“锁定”一个对象是什么意思。

Foobar foobar = new Foobar();

synchronized (foobar) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

您可能会说当线程在synchronized块中时 foobar 对象被“锁定” 。但这对程序有什么作用呢?许多新手错误地认为它会阻止其他线程访问该对象。但是,事实并非如此。是什么synchronized呢-同步的唯一的事情那样-是要保证不超过一个线程可以对同一对象在同一时间同步。

上例中程序员的意图可能是防止其他线程看到 foobar 处于不一致状态。在这种情况下,访问 foobar 的每个方法和每个代码片段都必须在 foobar 上同步。把 foobar 想象成有很多门的大房间。使用 foobar 的每种方法就像一扇不同的门。如果你想让人们远离房间,只锁一扇门是无济于事的。你必须锁定所有这些。

所以现在,对于你的问题:

当我们说通过同步静态方法实现类级锁定时会发生什么?

简单的。这个:

class Foobar {
    static synchonized void do_something() {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

与此完全相同:

class Foobar {
    static void do_something() {
        synchronized(Foobar.class) {
            ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

你总是在一个对象上同步。好吧,一个类就是一个对象。当一个static方法是 时synchronized,这仅仅意味着方法体在类对象上是同步的。

由于一个类是一个单例对象,这意味着没有两个线程可以同时进入同一个静态同步方法。在我之前的示例中,变量 foobar 可以在不同时间引用不同的对象,但在静态示例中, Foobar.class 保证始终引用相同的单例。


编辑:正如@Danny 指出的那样,在 Foobar 类上同步的块(我的第二个示例)与在 Foobar 类的实例上同步的块(我的第一个示例)之间没有联系。实例和类对象是两个不同的对象,因此没有什么可以阻止一个线程在实例上同步,而另一个线程在类上同步。同样,没有什么可以阻止两个不同的线程在两个不同的实例上同步。新手经常犯的另一个错误是认为一次只有一个线程可以进入这个synchronized块:

Integer n = ...;

synchronized (n) {
    n = n+1;
    ...
}
Run Code Online (Sandbox Code Playgroud)

但事实并非如此。被锁定的不是变量 n,而是 Integer 类的特定实例。每个进入块的线程都会创建一个新的 Integer 实例并将其分配给 n。因此,当下一个线程出现时,n 不再指代第一个线程已同步的同一个实例。