What is difference between Semaphore and Mutex in Java - Producer consumer problem with semaphore and mutex

Semaphore :- It is a variable used for controlling access to a common resource by multiple processes/threads in a concurrent system. In other words, semaphore is used to manage how many units of resources are available in multi-process or multi-threaded environment.
Possible value of a semaphore can vary from 0 to N, where is N is maximum units of shared resources allowed in the given system.
There are two type of semaphore - 
1. Counting semaphore (Values varies from 0 to N)
2. Binary semaphore (Values either 0  or  1)
Note:- Java's semaphore is a counting semaphor.
 
Mutex
:- It is basically mutual exclusion. In other words, only one thread is allowed to acquire the resource at a time. When one thread acquires the resource, no other thread is allowed to acquire the resource until the thread owning the resource releases. All threads waiting for acquiring resource would be blocked.
At high level, binary semaphore is similar to Mutex. Binary semaphore can act as Mutex. However, there is fundamental difference between Mutex and Semaphore :-  the concept of "ownership".
Semaphores have no notion of ownership, this means that any thread can release a semaphore, Whereas a mutex does have the concept of ownership The process that locked the mutex is supposed to unlock it.

Mutex primary use is to guard shared resources in multi-threaded environment.

In summary, semaphore provides singling mechanism and mutex provides locking mechanism(to synchronize access to a resource). 

When do we use semaphore and Mutex :- The usefulness of Mutex and Semaphore lies in - how many threads are allowed to acquire the resource at once ?

If answer is one - Mutex is suitable candidate.
Otherwise Semaphore as it allows multiple threads(equal to number of permitted semaphore values) to access shared resources.


Below sample code lines presents solution of producer-consumer problem using semaphore and Mutex(binary semaphore).


package com.dev.thread;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Semaphore;

public class ProducerConsumerUsingSemaphore1 {

 static List<Integer> list = new LinkedList<Integer>(); // shared resource.
 static Semaphore semaphore = new Semaphore(0);
 static Semaphore mutex = new Semaphore(1);// Binary semaphore
 static int value;
 static int N = 0;

 public static void main(String[] args) {
  // Multiple producer and multiple consumer
  Thread tp = new Thread(new Producer("producer-0"));
  Thread tp1 = new Thread(new Producer("producer-1"));
  Thread tc = new Thread(new Consumer("consumer-0"));
  Thread tc1 = new Thread(new Consumer("consumer-1"));
  tp.start();
  tc.start();
  tc1.start();
  tp1.start();
 }

 static class Producer implements Runnable {
  String name;

  public Producer(String name) {
   this.name = name;
  }

  public void run() {
   try {

    while (true) {
     mutex.acquire(); //critical section start 
     System.out.println("Producer \"" + name + "\" Write: " + N);
     list.add(new Integer(N++));
     mutex.release();
     semaphore.release(1);
     Thread.sleep(400);
    }
   } catch (Exception x) {
    x.printStackTrace();
   }
  }

 }

 static class Consumer implements Runnable {
  String name;

  public Consumer(String name) {
   this.name = name;
  }

  public void run() {
   try {
    while (true) {
     semaphore.acquire(1);// Acquires a permit from semaphore
     mutex.acquire(); // Begin critical section guarded by mutex
     System.out.println("Consumer \"" + name + "\" read: "
       + list.remove(0));
     mutex.release();
    }
   } catch (Exception x) {
    x.printStackTrace();
   }

  }

 }
}

In producer class run method, using mutex only one producer thread to enter into critical section and update List. Once acquire is called on a given binary semaphore, it blocks other thread and allows one thread to update List. Finally, semaphore is released for which consumer might be waiting.
Similarly, in consumer class run method, semaphore permit is acquired by a thread and value read/removed from list.

Sample output:-
Producer "producer-0" Write: 0
Consumer "consumer-0" read: 0
Producer "producer-1" Write: 1
Consumer "consumer-1" read: 1
Producer "producer-0" Write: 2
Consumer "consumer-0" read: 2
Producer "producer-1" Write: 3
Consumer "consumer-1" read: 3
Producer "producer-0" Write: 4
.......

Question
:- What are other ways to solve producer consumer problem ?
1. Using synchronized keyword and wait()/notify() methods
2. Using concurrent queue interface BlockingQueue.
3. Using java 5 Lock interface and Condition variable.

1 Comments

Previous Post Next Post