我知道锁定概念与静态和非静态方法的同步分别锁定类和实例。我无法理解的是,如何实现类级别锁定?我的意思是,课程只是一个模板,没有任何物理意义。那么,当我们说通过同步静态方法实现类级别锁定时会发生什么呢?该类的所有对象是否被锁定或其他进程?
我可以通过搜索找到的是有类对象(Class.class)并且在此类对象上获取了锁。但那么该类的所有实例也是如何锁定的?
答案 0 :(得分:4)
该类的所有对象是否被锁定或其他进程?
首先,让我们谈谈“锁定”一个对象意味着什么。
Foobar foobar = new Foobar();
synchronized (foobar) {
...
}
当线程在synchronized
块中时,您可能会说foobar对象被“锁定”。但这对该计划有什么作用?许多新手错误地认为它会阻止其他线程访问该对象。但是,这不是真的。 synchronized
的作用 - 同步唯一的作用 - 是保证同一个对象上不能同时同步一个以上的线程。
程序员在上面的示例中的意图可能是阻止其他线程在不一致的状态下看到foobar。在这种情况下,访问foobar的每个方法和每个代码片段都必须在foobar上同步。想象foobar是一个有很多门的大房间。使用foobar的每种方法都像一扇不同的门。如果你想让人们离开房间,只能锁上一扇门是没有用的。你必须锁定所有。
现在,问你的问题:
当我们说通过同步静态方法实现类级锁定时会发生什么呢?
简单。这样:
class Foobar {
static synchonized void do_something() {
...
}
}
与此完全相同:
class Foobar {
static void do_something() {
synchronized(Foobar.class) {
...
}
}
}
您始终在对象上进行同步。好吧,类是一个对象。当static
方法为synchronized
时,这意味着方法体在类对象上同步。
由于类是 singleton 对象,这意味着没有两个线程可以同时进入同一个静态同步方法。在我之前的例子中,变量foobar可以在不同的时间引用不同的对象,但在静态示例中,Foobar.class始终保证引用相同的单例。
编辑:正如@Danny指出的那样,在Foobar类上同步的块(我的第二个例子)和在实例上同步的块之间没有连接。 Foobar类(我的第一个例子)。实例和类对象是两个不同的对象,因此没有什么可以阻止一个线程在实例上进行同步,而另一个线程在类上同步。同样,没有什么能阻止两个不同的线程在两个不同的实例上同步。新手经常犯的另一个错误是认为一次只有一个线程可以进入synchronized
块:
Integer n = ...;
synchronized (n) {
n = n+1;
...
}
但事实并非如此。它不是被锁定的变量n,它是Integer类的特定实例。进入块的每个线程都会创建一个新的Integer实例并将其分配给n。因此,当下一个线程出现时,n不再引用第一个线程已同步的相同实例。