【问题标题】:Correct implementation of lock for semaphore? [duplicate]信号量锁的正确实现? [复制]
【发布时间】:2014-06-06 17:32:11
【问题描述】:

我不确定以下实现是否正确。我的原因是,如果当前线程在等待发出信号时被中断,finally 块将被调用,但由于它没有持有锁,IllegalMonitorStateException 将被抛出。在这种情况下,我是否正确实现了 try-finally 块,还是应该实现一个?

  public void acquire() throws InterruptedException {
    try {
      lock.lockInterruptibly();
      while (permits == 0) {
        condition.await();
      }
      permits--;
    }
    finally {
      lock.unlock();
    }
  }

【问题讨论】:

  • 不正确,为什么不用监视器?
  • ...我敢指出java.util.concurrent.Semaphore 已经存在吗?
  • 我正在使用ReentrantLockCondition 实现信号量。这是一个任务。
  • @BJPeterDeLaCruz 您应该被告知,您必须在没有他人帮助的情况下自己完成作业,否则将被视为作弊。
  • @RomanC 感谢您的建议。放心,我已经完成了任务。 :) 但我不确定这个案子。

标签: java concurrency semaphore


【解决方案1】:

不确定我对问题的理解是否正确,但您应该只在资源分配后尝试-finally

  public void acquire() throws InterruptedException {
    lock.lockInterruptibly(); // allocate resource before try
    try {
      while (permits == 0) {
        condition.await();
      }
      permits--;
    }
    finally {
      lock.unlock();
    }
  }

我不知道为什么所有学校都这样做,例如Sun's official page on finally,建议在 finally 子句中的 try 内分配(这样你就需要 if(allocated) {release})。这是愚蠢的国际海事组织。为什么大家都建​​议在try里面配置?

【讨论】:

  • 我的问题是,如果线程在释放锁后被中断(在等待许可数变为可用时)会发生什么? finally 块中的代码将被调用,但它没有持有锁,因此将在那里抛出异常。对吗?
  • 我不知道,但是你拿到钥匙后不拿着怎么叫解锁?锁定的成功结果是否意味着您一直持有它直到调用解锁?中断与丢失密钥有什么关系?在到达 finally 之前如何释放锁?
【解决方案2】:

一个好问题。实际上,我自己也对结果感到惊讶。

如果出现InterruptedException,条件将停止awaiting,然后执行finally。显然不会拥有锁并传播IllegalMonitorStateException

【讨论】:

    【解决方案3】:

    这个解决方案怎么样?

      public void acquire() throws InterruptedException {
        lock.lockInterruptibly();
        while (permits == 0) {
          condition.await();
        }
        try {
          permits--;
        }
        finally {
          lock.unlock();
        }
      }
    

    await 返回时,当前线程将拥有锁。如果它在等待其他线程发出信号时被中断(即它没有锁),acquire 将把InterruptedException 扔回给调用者。

    【讨论】:

    • I'm satisfied with this solution: 我不是。如果InterruptedException 发生在condition.await() 期间会发生什么。在那种情况下,锁怎么会是unlocked
    • 但是根据文档,在调用该方法时会释放锁,对吗?或者你是说线程可以在锁被释放前的毫秒内的某个时间被中断?
    • 是的,没错。假设线程在lock.lockInterruptibly() 之后和condition.await() 之前被中断。在这种情况下,它仍然拥有锁,并且对await() 的任何调用都会立即抛出异常并且不会解锁。在这种情况下,您会遇到潜在的死锁。
    猜你喜欢
    • 2012-03-01
    • 2016-02-10
    • 2010-10-30
    • 2019-10-29
    • 2017-10-03
    • 1970-01-01
    • 2021-05-09
    • 2011-08-25
    相关资源
    最近更新 更多