2012-09-24 28 views
1

为了理解计数信号量的工作,我决定实现一个简单的版本。 我想验证我的当前实现实际上是在一个正确的执行,我还没有错过什么明显简单的计数信号灯

public class CountingSemaphore { 
    private int limit; 

    public CountingSemaphore(int limit) { 
     this.limit = limit; 
    } 

    public synchronized void acquire() { 
     try { 
      if (limit == 0) 
       wait(); 

      limit--; 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public synchronized void release() { 
     try { 
      if(limit == 0) 
       notifyAll(); 

      limit++; 
     }catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 

} 

回答

3

这应该只是一个细节的工作。
由于您使用notifyAll()(和@JBNizet指出,由于虚假唤醒的风险),您可以唤醒几个等待的线程,所有这些线程都将被释放并减少limit
变化

if (limit == 0) 
    wait(); 

while (limit == 0) { 
    wait(); 
} 

,你应该罚款。

+0

+1:我看到了虚假唤醒问题,但错过了明显的逻辑问题。咄! –

3

wait()应始终将其包含在while循环中,以检查由于虚假唤醒引起的唤醒情况。阅读the javadoc了解更多信息。

发现异常并吞咽它们是一种非常糟糕的做法。你的acquire()方法应该抛出InterruptedException。您的发布方法不应该捕获异常。

而且我不会将信号量本身用作锁:外部类可以使用它来同步完全不相关的内容,并且可能导致性能不佳或死锁。我会使用一个私人的最终锁定对象。

+0

似乎粗鲁报价而不是+1。 :) – Keppil

0

从客户端的角度来看,你应该强迫我用你的信号值> = 0

0

你在你的代码中的问题,当你调用释放你打电话通知所有,但这里

public synchronized void acquire() { 
     try { 
      if (limit == 0) 
       wait(); 

      limit--; 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

所有正在等待的线程都被释放,并且您可以通过git限制< 0,并且您sem打破 这里常见的解决方案是使用循环。

while(limit == 0){ 
    wait(); 
}