Java - Thread Semaphores

Introduction

A semaphore controls the number of threads that can access a resource.

A synchronized block allows only one thread to access a resource, whereas a semaphore allows N threads to access a resource.

If N is one, a semaphore is acting as a synchronized block.

Example

Suppose there is a restaurant with three dining tables.

A person must take a token for a table.

After eating, he will return the token.

If no token is available he must wait.

Semaphore class from java.util.concurrent package represents the semaphore synchronizer.

You create a semaphore as follows:

final int MAX_PERMITS = 3;
Semaphore s = new Semaphores(MAX_PERMITS);

To create a fair Semaphore

Semaphore s = new Semaphores(MAX_PERMITS, true); // A fair semaphore

A fair semaphore will guarantee first come first serve.

To acquire a permit, use the acquire() method.

It returns immediately if a permit is available. It blocks if a permit is not available.

To release a permit, use the release() method.

Demo

import java.util.Random;
import java.util.concurrent.Semaphore;

public class Main {
  public static void main(String[] args) {
    // Create a restaurant with three dining tables
    Restaurant restaurant = new Restaurant(3);
    // Create five customers
    for (int i = 1; i <= 5; i++) {
      RestaurantCustomer c = new RestaurantCustomer(restaurant, i);
      c.start();// w w  w . j  a  v a  2s . c  om
    }
  }
}
class Restaurant {
  private Semaphore tables;
  public Restaurant(int tablesCount) {
    this.tables = new Semaphore(tablesCount);
  }
  public void getTable(int customerID) throws Exception{
      System.out.println("Customer #" + customerID
          + " is trying to get a table.");
      tables.acquire();
      System.out.println("Customer #" + customerID + " got a table.");
  }

  public void returnTable(int customerID) {
    System.out.println("Customer #" + customerID + " returned a table.");
    tables.release();
  }

}

class RestaurantCustomer extends Thread {
  private Restaurant r;
  private int customerID;
  public RestaurantCustomer(Restaurant r, int customerID) {
    this.r = r;
    this.customerID = customerID;
  }

  public void run() {
    try {
      r.getTable(this.customerID); // Get a table      
      int eatingTime = 3;
      System.out.println("Customer #" + this.customerID + " will eat for "
          + eatingTime + " seconds.");
      Thread.sleep(eatingTime * 1000);
      System.out.println("Customer #" + this.customerID + " is done eating.");
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      r.returnTable(this.customerID);
    }
  }
}

Result