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();
        }
    }

}
4

4 回答 4

3

除了一个细节外,这应该可以工作。
由于您使用notifyAll(), (正如@JBNizet 指出的那样,由于存在虚假唤醒的风险),您可以唤醒几个等待线程,所有这些线程都将被释放和减少limit
改变

if (limit == 0)
    wait();

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

你应该没事。

于 2012-09-24T19:41:19.253 回答
3

wait()由于虚假唤醒,应始终将其包含在检查唤醒条件的 while 循环中。阅读javadoc以获取更多信息。

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

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

于 2012-09-24T19:41:38.390 回答
0

从客户的角度来看,您应该强迫我使用值 >= 0 的信号量。

于 2012-09-24T19:42:42.713 回答
0

你的代码有问题,当你调用 release 时,你调用 notify all 除了这里

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

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

所有等待的线程都被释放,你可以 git limit<0,你会打破这里的常见解决方案是使用循环。

 while(limit == 0){
     wait();
}
于 2012-09-24T19:42:47.527 回答