2

我需要一个具有以下功能的信号量:

  1. 它应该是非阻塞的,即如果线程无法获得许可,它应该更进一步而无需等待
  2. 它应该是不可重入的,即如果同一个线程两次进入受保护的代码段,它应该带走两个许可而不是一个

我写了以下代码:

public class SimpleSemaphore
{

    private int permits;

    private AtomicLong counter = new AtomicLong();

    SimpleSemaphore(int permits)
    {
        this.permits = permits;
    }

    boolean acquire()
    {

        if (counter.incrementAndGet() < permits)
        {
            return true;
        }
        else
        {
            counter.decrementAndGet();
            return false;
        }

    }

    void release()
    {
        counter.decrementAndGet();

    }
}

另一种选择是这个信号量:

public class EasySemaphore
{

    private int permits;

    private AtomicLong counter = new AtomicLong();

    EasySemaphore(int permits)
    {
        this.permits = permits;
    }

    boolean acquire()
    {
        long index = counter.get();

        if (index < permits)
        {
            if (counter.compareAndSet(index, index + 1))
            {
                return true;
            }
        }

        return false;
    }

    void release()
    {
        counter.decrementAndGet();
    }
}

这两种实现都是线程安全且正确的吗?哪一个更好?你将如何完成这项任务?

4

2 回答 2

7

不是java.util.concurrent.Semaphore已经做了这一切吗?

它有一个tryAcquire非阻塞获取,它维护一个简单的剩余许可计数(同一个线程可以取出多个许可)。

于 2012-09-26T08:22:03.473 回答
0

我会说第二个更好,因为计数器永远不会大于 0(并且它的效率略高)

我会使用一个循环,否则当仍然有许可时,你可以让方法失败。

public class EasySemaphore {
    private final AtomicInteger counter;

    EasySemaphore(int permits) {
        counter = new AtomicInteger(permits);
    }

    boolean acquire() {
        // highly unlikely to loop more than once.
        while(true) {
            int count = counter.get();
            if (count <= 0) return false;
            if (counter.compareAndSet(count, count -1)) 
                return true;
        }
    }

    void release() {
        counter.incrementAndGet();
    }
}
于 2012-09-26T08:23:18.293 回答