7

我知道如果使用 ReentrantLock,它允许同一个线程多次获取同一个锁。在内部,它有一个计数器来计算获得锁的次数。如果您两次获得相同的锁,则需要释放两次。但我的问题是,为什么有人要多次获取锁,一次获取就足够了吗?有人可以给我一个常见的用例吗?

4

4 回答 4

13

考虑以下情况,您需要一组不是原子的操作,是原子的。例如,您可能想要设置一个数组的值,但在设置时返回其当前值。(为简洁起见,最终删除)。

final ReentrantLock lock = new ReentrantLock();

final Object[] objects = new Object[10]
public Object setAndReturnPrevious(int index, Object val){
   lock.lock();
      Object prev = get(index);
      set(index,val);
      return prev;
   lock.unlock();
}
public void set(int index, Object val){
    lock.lock();
         objects[index] = val;
    lock.unlock();
}
public Object get(index index){...}

如果 ReentrantLock 不是可重入的,您将在get(index)

于 2013-09-03T15:38:25.927 回答
4

假设在一个类中,您有两个方法 m1 和 m2,它们都是同步的,并且 m2 正在调用 m1。在这种情况下,如果线程 a 已在 m1 上锁定并且不允许再次锁定,则该线程将继续等待调用 m2(因为它已经拥有锁定)

于 2013-09-03T15:33:19.573 回答
3

考虑这个同步的例子。这同样适用于锁,但有更多的代码。

synchronized int getSum() {
     return getValue() + getOtherValue();
}

synchronized int getValue() {
     return value;
}

synchronized int getOtherValue() {
     return value;
}

避免重入的唯一方法是创建每个方法的锁定和解锁版本。但是,如果您有两个实例 A 和 B。A 调用 B,B 又调用 A。B 如何知道不调用 A 中的同步方法。

于 2013-09-03T15:54:14.053 回答
1

一些人认为应该避免重入锁定。在关键部分,您应该确切地知道发生了什么。如果本地临界区可能调用可能回调本地代码的外部代码,这看起来非常复杂且具有潜在危险。最好只有几个定义明确的关键部分,只包含本地代码。

于 2013-09-03T16:03:39.727 回答