How will you implement your custom threadsafe Semaphore in Java

Carvia Tech | May 05, 2019 | 2 min read | 55 views


We can implement a custom semaphore using ReentrantLock and Condition classes provided by Java. However this implementation is just for illustration purpose and not for production use.

Java Docs: Condition and Lock Interface

Condition factors out the Object monitor methods (wait, notify and notifyAll) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitrary Lock implementations. Where a Lock replaces the use of synchronized methods and statements, a Condition replaces the use of the Object monitor methods.

Not for production use, instead use java.util.concurrent.Semaphore
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@ThreadSafe
public class CustomSemaphore {  (1)
    private final Lock lock = new ReentrantLock();
    // CONDITION PREDICATE: permitsAvailable (permits > 0)
    private final Condition permitsAvailable = lock.newCondition();

    @GuardedBy("lock")
    private int permits;

    CustomSemaphore(int initialPermits) {
        lock.lock();
        try {
            permits = initialPermits;
        } finally {
            lock.unlock();
        }
    }

    /**
     * Blocks until permitsAvailable (permit > 0)
     * @throws InterruptedException
     */
    public void acquire() throws InterruptedException {
        lock.lock();
        try {
            while (permits <= 0)
                permitsAvailable.await();
            --permits;
        } finally {
            lock.unlock();
        }
    }

    /**
     * Release a single permit and notifies threads waiting on permitsAvailable Condition
     */
    public void release() {
        lock.lock();
        try {
            ++permits;
            permitsAvailable.signal();
        } finally {
            lock.unlock();
        }
    }

}
1 Derived from Java Concurrency in Practice: Chapter14. BuildingCustomSynchronizers

Code walk-through

  1. A semaphore contains a number of permits and provides two methods - acquire() and release()

  2. acquire() method is a blocking call which will decrease number of available permits by one, else wait for a permit to be available. Signalling is done through Condition interface (which is permitsAvailable in our case)

  3. release() method will increment number of permits by one and notify all threads waiting on condition (permitsAvailable), so that one of waiting thread (if any) can acquire the next lock.

  4. As you can see, both methods (acquire and release) call lock() on lock object, this is necessary for memory visibility and atomicity of shared mutable state (permits in this case)


Top articles in this category:
  1. How will you calculate factorial of a large number in Java
  2. What is Deadlock in Java? How to troubleshoot and how to avoid deadlock
  3. Explain the threading Jargon in Java
  4. How to implement Thread pool in Java without executor framework
  5. How will you implement a Blocking Queue in Java
  6. What is ThreadLocal in Java, where will you use this class
  7. How will you increment each element of an Integer array, using parallel operation



Find more on this topic:
Core Java image
Core Java

Core Java - OOP Concepts, Garbage Collection, Multi-threading, Collections Framework, Java 8 Features, Lambda Functions, Streams.

Last updated 1 month ago


Recommended books for interview preparation:

This website uses cookies to ensure you get the best experience on our website. more info