How will you implement your custom threadsafe Semaphore in Java

Carvia Tech | May 05, 2019 | 2 min read | 740 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. Custom Thread pool implementation in Java
  2. Explain the threading Jargon in Java
  3. Java 8 Parallel Stream custom ThreadPool
  4. Troubleshooting Deadlock in Java
  5. How will you increment each element of an Integer array, using parallel operation
  6. Allow insecure SSL in Java 11 HttpClient
  7. How will you handle ConcurrentModificationException in Java


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 week ago


Recommended books for interview preparation:

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