我读到Java中的锁是在实例(对象)的基础上获得的(在实例方法的情况下)
也可以在类的对象上获得锁(在静态方法的情况下)。
但我想知道一个特定对象一次可以获得多少个锁?
一个对象一次可以拥有多个锁吗?
如果是,请举例说明。
请帮我理清我的概念。
我读到Java中的锁是在实例(对象)的基础上获得的(在实例方法的情况下)
也可以在类的对象上获得锁(在静态方法的情况下)。
但我想知道一个特定对象一次可以获得多少个锁?
一个对象一次可以拥有多个锁吗?
如果是,请举例说明。
请帮我理清我的概念。
每个同步块仅在一个对象上。对象不会拥有锁。它是执行线程,它锁定一个对象以便对其进行处理。
总是在对象上获得锁。例如,以下是可以获得锁的两个实例。第一个锁定类(对象)的实例。
Object obj = new Object();
synchronized(obj) {
workOnIt(obj);
}
第二个看起来像是锁定了一个班级。但是 Test.class 是我的 Test 类的 java.lang.Class 实例的特殊表示。
synchronized(Test.class) {
// call some static method here
}
一个线程可以为多个对象持有多个锁。但是您必须自担风险(以避免死锁或性能下降)
synchronized (obj1)
{
synchronized (obj2)
{
// do sth. against obj1 and obj2
}
}
考虑一个带有同步块的方法(改编自JVMS)
public void foo(Object f) {
synchronized(f) {
doSomething();
}
}
让我们把它翻译成伪代码(Java 和字节码的混合!!!):
public void foo(Object f) {
monitorenter(f);
try {
doSomething();
monitorexit(f);
} catch(Throwable e) {
monitorexit(f);
throw e;
}
}
如果字节码指令是 java 方法monitorenter
,这就是它的样子。monitorexit
每个对象都有一个监视器。如果一个线程进入监视器并且未获取(锁定,获取)监视器,则它获取(锁定,获取)监视器并调用doSomething()
(这是下一行)。
如果现在第二个线程出现并尝试进入 object 上的监视器f
,则它会在此位置等待,直到f
释放 object 上的监视器。当第一个线程调用两条monitorexit
指令之一(字节码!!)时,监视器被释放。
回到问题——一个线程可以输入多少个监视器?可能没有限制(堆栈大小限制除外)。如果doSomething
是另一种同步方法并使用 Object 的监视器g
,则线程一个也将进入该监视器并获取监视器g
(如果可用)。
获得锁的不是对象,而是进入对象监视器的线程,并且该进程正在“锁定”。
一个锁(以同步块或方法的形式)有一个主要作用:同时只有一个线程可以进入这个对象的一个同步块/方法,即只有一个线程可以是这个锁的所有者(或“监视器”,因为它在 JLS 中被调用)。
(另一个影响是,当在同一监视器上的稍后同步块中(或之后)时,保证在一个同步块内(或之前)更改的所有变量在其他线程中可见。)
您在此块中使用多少对象/变量是您的自由决定,但通常您对所有以某种方式组合在一起的数据使用一个锁,并且不应单独修改/访问。
请注意,锁定对象本身并不能避免其他线程更改/使用此对象,它只会避免其他线程在此对象上同步。所以一定要同步所有相关的方法(并且没有公共变量)。
当您使用静态方法获得类上的锁时,您将像其他任何对象一样获得对象上的锁。
class A {
synchronized void foo() {
// do something.
}
static synchronized void bar() {
// do something.
}
}
基本上是一样的
class A {
void foo() {
Object locked = this;
synchronized(locked) {
// do something.
}
}
static void bar() {
Object locked = A.this;
synchronized(locked) {
// do something.
}
}
}
唯一可能对其拥有的锁数量感到困惑的类是 a 的实例Lock
。这是一种不同风格的锁,但也是一个对象,所以也有一个标准的锁。这样你就可以
Lock lock = new ReentrantLock();
lock.lock();
lock.unlock();
但是,您可能会混淆
Lock lock = new ReentrantLock();
synchronized(lock) { // don't do this.
lock.wait(); // argh.
}