14

Semaphores

A semaphore keeps a count of how many times a limited resource is being used. When a component needs a shared specific resource, it tries to acquire it from the semaphore which manages it. If the resource is not available, the requesting thread is automatically blocked. As soon as another component releases the resource, one of the waiting threads is awaken and regains control.

  1. public class Semaphore {
  2.     private int count;
  3.  
  4.     public Semaphore(int n) {
  5.         this.count = n;
  6.     }
  7.  
  8.     public synchronized void acquire() {
  9.         while (count == 0) {
  10.             try {
  11.                 wait();
  12.             }
  13.             catch (InterruptedException e) {
  14.             }
  15.         }
  16.         count--;
  17.     }
  18.  
  19.     public synchronized void release() {
  20.         count++;
  21.         notify();
  22.     }
  23. }

An instance of Semaphore is always initialized with the total number of available units of the resource it manages. The method acquire blocks the execution thread while the counter of the resource is at zero. If the resource is available, the counter is decremented of one and the execution continues normally. The method release increments the counter of one and awakes all the waiting threads of execution with a call to notify. One of them will regain control in the loop of the method acquire and will be able to continue its execution after having reserved the resource.

Note that acquire and release are synchronized in order to prevent any interferences with the counter.

To test Semaphore, we'll create a series of threads of execution which will all try at the same time to use the same limited resource for a given time.

  1. public class SemaphoreTest {
  2.     private Semaphore sema = new Semaphore(2);
  3.  
  4.     public void go() {
  5.         for (int i = 0; i < 7; i++)
  6.             (new Thread(new Consumer(i + 1, sema))).start();
  7.     }
  8.  
  9.     private class Consumer implements Runnable {
  10.         private Semaphore sema;
  11.  
  12.         private int id;
  13.  
  14.         Consumer(int id, Semaphore sema) {
  15.             this.sema = sema;
  16.             this.id = id;
  17.         }
  18.  
  19.         public void run() {
  20.             System.out.println(id + " - " + "Acquiring resource");
  21.             sema.acquire();
  22.             System.out.println(id + " - " + "Resource is locked");
  23.             try {
  24.                 Thread.sleep((long) (Math.random() * 1000));
  25.             }
  26.             catch (InterruptedException e) {
  27.             }
  28.             System.out.println(id + " - " + "Releasing resource");
  29.             sema.release();
  30.         }
  31.     }
  32.  
  33.     public static void main(String args[]) {
  34.         (new SemaphoreTest()).go();
  35.     }
  36. }

The program creates a Semaphore which allows the simultaneous use of two units of a resource, then it starts the parallel execution of seven instances of Consumer which all have acces to the semaphore. A Consumer prints a message before it tries to acquire the resource, calls acquire, prints a message if the resource is available, does something for a while, prints a last message before it releases the resource and calls release.

Note that the program doesn't decide when it can take the resource and continue its execution. All the logic is in Semaphore.

$ javac SemaphoreTest.java
$ java SemaphoreTest
1 - Acquiring resource
1 - Resource is locked
2 - Acquiring resource
2 - Resource is locked
3 - Acquiring resource
4 - Acquiring resource
...
2 - Releasing resource
3 - Resource is locked
3 - Releasing resource
4 - Resource is locked
4 - Releasing resource
1 - Releasing resource
5 - Resource is locked
...

The execution order of the concurrent instances of Consumer can vary.

Comments

Your comment:
[p] [b] [i] [u] [s] [quote] [pre] [br] [code] [url] [email] strip help 2000

Enter a maximum of 2000 characters.
Improve the presentation of your text with the following formatting tags:
[p]paragraph[/p], [b]bold[/b], [i]italics[/i], [u]underline[/u], [s]strike[/s], [quote]citation[/quote], [pre]as is[/pre], [br]line break,
[url]http://www.izend.org[/url], [url=http://www.izend.org]site[/url], [email]izend@izend.org[/email], [email=izend@izend.org]izend[/email],
[code]command[/code], [code=language]source code in c, java, php, html, javascript, xml, css, sql, bash, dos, make, etc.[/code].