Semaphore

A Semaphore is like a Lock, except that a Lock allows only one thread to access a resource at a time, a semaphore allows a specific limit number of threads to access a resource.

Semaphore is more versatile then a Lock. It can be used to limit access to a resource pool, such as a fixed number of database connections. It can also be used to limit the number of concurrent tasks.

import java.util.concurrent.Semaphore;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Semaphore semaphore = new Semaphore(2);

        Runnable task = () -> {
            try {
                String name = Thread.currentThread().getName();

                System.out.println(name + " is trying to acquire a permit...");
                semaphore.acquire();

                System.out.println(name + " has acquired a permit and is working...");
                Thread.sleep(2000);

                semaphore.release();
                System.out.println(name + " has released a permit.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        new Thread(task).start();
        new Thread(task).start();
        new Thread(task).start();
        new Thread(task).start();
    }
}

Expected output:

Thread-0 is trying to acquire a permit...
Thread-1 is trying to acquire a permit...
Thread-1 has acquired a permit and is working...
Thread-2 is trying to acquire a permit...
Thread-3 is trying to acquire a permit...
Thread-0 has acquired a permit and is working...
Thread-2 has acquired a permit and is working...
Thread-1 has released a permit.
Thread-3 has acquired a permit and is working...
Thread-0 has released a permit.
Thread-2 has released a permit.
Thread-3 has released a permit.