0

我读到Java中的锁是在实例(对象)的基础上获得的(在实例方法的情况下)
也可以在类的对象上获得锁(在静态方法的情况下)。

但我想知道一个特定对象一次可以获得多少个锁

一个对象一次可以拥有多个锁吗?
如果是,请举例说明。

请帮我理清我的概念。

4

5 回答 5

2

每个同步块仅在一个对象上。对象不会拥有锁。它是执行线程,它锁定一个对象以便对其进行处理。

总是在对象上获得锁。例如,以下是可以获得锁的两个实例。第一个锁定类(对象)的实例。

Object obj = new Object();

synchronized(obj) {
    workOnIt(obj);
}

第二个看起来像是锁定了一个班级。但是 Test.class 是我的 Test 类的 java.lang.Class 实例的特殊表示。

synchronized(Test.class) {
    // call some static method here
}
于 2011-02-21T15:57:11.403 回答
1

一个线程可以为多个对象持有多个锁。但是您必须自担风险(以避免死锁或性能下降)

synchronized (obj1)
{
  synchronized (obj2)
  {
    // do sth. against obj1 and obj2 
  }
}
于 2011-02-21T16:01:25.970 回答
0

考虑一个带有同步块的方法(改编自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(如果可用)。

获得锁的不是对象,而是进入对象监视器的线程,并且该进程正在“锁定”。

于 2011-02-21T16:27:40.627 回答
0

一个锁(以同步块或方法的形式)有一个主要作用:同时只有一个线程可以进入这个对象的一个​​同步块/方法,即只有一个线程可以是这个锁的所有者(或“监视器”,因为它在 JLS 中被调用)。

(另一个影响是,当在同一监视器上的稍后同步块中(或之后)时,保证在一个同步块内(或之前)更改的所有变量在其他线程中可见。)

您在此块中使用多少对象/变量是您的自由决定,但通常您对所有以某种方式组合在一起的数据使用一个锁,并且不应单独修改/访问。

请注意,锁定对象本身并不能避免其他线程更改/使用此对象,它只会避免其他线程在此对象上同步。所以一定要同步所有相关的方法(并且没有公共变量)。

于 2011-02-21T16:13:34.410 回答
0

当您使用静态方法获得类上的锁时,您将像其他任何对象一样获得对象上的锁。

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.
}
于 2011-02-21T16:45:51.663 回答