Semaphore guards a shared resource allowing only a defined number of threads to operate at a time.

General behavior is as follows:

Conceptually, a Semaphore maintains a set of permits. Each acquire blocks if necessary until a permit is available, and then takes it. Each release adds a permit, potentially releasing a blocking acquirer. However, no actual permit objects are used; the Semaphore just keeps a count of the number available and acts accordingly.

Let's say, we have a restaurant and we have following requirements:

  • Only 3 customers can dine at the restaurant

To achieve this, we will create a Semaphore with the permit count as 3. Each thread will acquire a permit if available. When all permits are given, other threads will wait for a permit owner to release its  permit.

public class SemaphoreTest {

    public static void main(String[] args) throws InterruptedException {
        semaphore();
    }

    public static void semaphore() throws InterruptedException {
        final Restaurant restaurant = new Restaurant();
        final ExecutorService threadPool = Executors.newFixedThreadPool(3);
        class Customer implements Runnable {

            @Override
            public void run() {
                try {
                    restaurant.eat();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        threadPool.execute(new Customer());
        threadPool.execute(new Customer());
        threadPool.execute(new Customer());
        threadPool.execute(new Customer());
        threadPool.execute(new Customer());
        threadPool.execute(new Customer());
        threadPool.shutdown();
        threadPool.awaitTermination(10, TimeUnit.SECONDS);
    }

    static class Restaurant {

        private final Semaphore semaphore = new Semaphore(3, true);
        private volatile AtomicInteger current = new AtomicInteger(0);

        public void eat() throws InterruptedException {
            semaphore.acquire();
            try {
                System.out.printf("%s - Current: %s%n", Thread.currentThread().getName(), current.incrementAndGet());
                sleep(100);
            } finally {
                System.out.printf("%s - Will be: %s%n", Thread.currentThread().getName(), current.decrementAndGet());
                semaphore.release();
            }
        }
    }
}