【问题标题】:java.concurrent.ReentrantLock - why we want to acquire the same lock multiple times [duplicate]java.concurrent.ReentrantLock - 为什么我们要多次获取同一个锁[重复]
【发布时间】:2013-09-06 21:53:36
【问题描述】:

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

【问题讨论】:

  • 这种事情经常发生在具有读/写的文件访问中
  • http://en.wikipedia.org/wiki/Semaphore_(programming) 这里有一些很好的类比。

标签: java multithreading reentrantlock


【解决方案1】:

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

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) 处死锁

【讨论】:

  • 现在说得通了,这将 ReentrantLock 与 synchronized(this) 区分开来,对吧?在这种情况下, sychronized(this) 会在 get(index) 处死锁。
  • @Shengjie 其实synchronized 也是可重入的,所以在这两种情况下你都不会死锁。
【解决方案2】:

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

【讨论】:

    【解决方案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 中的同步方法。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2019-12-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-14
        • 1970-01-01
        相关资源
        最近更新 更多