KutaBeach
KutaBeach

Reputation: 1495

Non-reentrant non-blocking semaphore in Java

I need a semaphore with the following features:

  1. it should be non-blocking, i.e. if the thread cannot get the permit it should go further without waiting
  2. it should be nonreentrant, i.e. if the same thread enters the guarded piece of code twice it should take away two permits instead of one

I have written the following code:

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

    }
}

Another option is this Semaphore:

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

Are the both implementations thread-safe and correct? Which one is better? How would you go about this task?

Upvotes: 2

Views: 2679

Answers (2)

Thilo
Thilo

Reputation: 262852

Doesn't java.util.concurrent.Semaphore already do all that?

It has a tryAcquire for non-blocking acquire, and it maintains a simple count of remaining permits (of which the same thread could take out more than one).

Upvotes: 7

Peter Lawrey
Peter Lawrey

Reputation: 533880

I would say the second one is better as the counter will never be greater thathan 0 (and its slightly more efficient)

I would use a loop otherwise you can have the method fail when there is still permits left.

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

Upvotes: 0

Related Questions