Thursday, August 10, 2017

Semarphores and Mutex

Java multi threads example to show you how to use Semaphore and Mutex to limit the number of threads to access resources.
  1. Semaphores – Restrict the number of threads that can access a resource. Example, limit max 10 connections to access a file simultaneously.
  2. Mutex – Only one thread to access a resource at once. Example, when a client is accessing a file, no one else should have access the same file at the same time.
Summary (Java Docs)
A counting semaphore. 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.
Semaphores are often used to restrict the number of threads than can access some (physical or logical) resource.
Before obtaining an item each thread must acquire a permit from the semaphore, guaranteeing that an item is available for use. When the thread has finished with the item it is returned back to the pool and a permit is returned to the semaphore, allowing another thread to acquire that item.

Working of semaphore

In general, to use a semaphore, the thread that wants access to the shared resource tries to acquire a permit.
§  If the semaphore’s count is greater than zero, then the thread acquires a permit, which causes the semaphore’s count to be decremented.
§  Otherwise, the thread will be blocked until a permit can be acquired.
§  When the thread no longer needs an access to the shared resource, it releases the permit, which causes the semaphore’s count to be incremented.
§  If there is another thread waiting for a permit, then that thread will acquire a permit at that time.

public class SemaphoreTest {
     public static void main(String[] args) throws InterruptedException {
          Semaphore sem = new Semaphore(1);
          sem.acquire();
          System.out.println(sem.availablePermits());
          sem.release();
          System.out.println(sem.availablePermits());
     }
}

Output

0
1
  
Below example show how to restrict number of connections to 10 having threads equal to 100.

/* Connection- Singleton class
 * Before Semaphore- 100 threads are getting connections simultaneously
 * After Semaphore - Max 10 threads can get connections and once connections released from 10 threads, next threads can get Connections
*/

class Connection {

     private Semaphore sem = new Semaphore(10,true);
     private int connections = 0;

     private Connection() {
     }
    
     private static Connection instance = new Connection();

     public static Connection getConnection() {
          return instance;
     }

     public void connect() throws InterruptedException {
     /* Out of 100 threads, first 10 threads acquired
        the permit and rest 90 waiting */
          sem.acquire();
          synchronized (this) {
          connections++;
        System.out.println("CUrrent COnnections "+ connections);  
          }
         
          Thread.sleep(5000);
         
      /* Same 10 thread enter this block and
         release connection and release permit as well
         Thus other 90 threads get the chance
         to acquire the permit and acquire the connection
      */
          synchronized (this) {
              connections--;
          }
          sem.release();
     }
}

/* Semaphore- Restrict number of threads that can access a resource */
public class SemaphoreTest {
     public static void main(String[] args) throws InterruptedException {
          ExecutorService executorService = Executors.newCachedThreadPool();
          for (int i = 1; i <= 100; i++) {
              executorService.execute(new Runnable() {

                   @Override
                   public void run() {
                        try {
                             Connection.getConnection().connect();
                        } catch (InterruptedException e) {
                             e.printStackTrace();
                        }
                   }
              });
          }
          executorService.shutdown();
          executorService.awaitTermination(1, TimeUnit.DAYS);
     }
}

Output
CUrrent COnnections 1
CUrrent COnnections 2
CUrrent COnnections 3
CUrrent COnnections 4
CUrrent COnnections 5
CUrrent COnnections 6
CUrrent COnnections 7
CUrrent COnnections 8
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 8
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 8
CUrrent COnnections 9
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 8
CUrrent COnnections 8
CUrrent COnnections 9
CUrrent COnnections 7
CUrrent COnnections 8
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 8
CUrrent COnnections 8
CUrrent COnnections 9
CUrrent COnnections 9
CUrrent COnnections 10
CUrrent COnnections 9
CUrrent COnnections 10

Example 2

public class SemaphoreImpl {
     Semaphore binary = new Semaphore(1);
      
     public static void main(String args[]) {
          final SemaphoreImpl test = new SemaphoreImpl();
          new Thread(() -> test.mutualExclusion()).start();
          new Thread(() -> test.mutualExclusion()).start();
     }
     /* Lock acquired by thread 1 by calling acquire() and no
      * other thread can proceed before thread 1 release the lock*/
     private void mutualExclusion() {
          try {
              binary.acquire();
              System.out.println(Thread.currentThread().getName() +
              " inside mutual exclusive region");
              Thread.sleep(1000);

          } catch (InterruptedException e) {
              e.printStackTrace();
          } finally {
              binary.release();
              System.out.println(Thread.currentThread().getName() +
              " outside of mutual exclusive region");
          }
     }
}

Output
Thread-0 inside mutual exclusive region
Thread-0 outside of mutual exclusive region
Thread-1 inside mutual exclusive region

Thread-1 outside of mutual exclusive region

Mutex
Mutex is the Semaphore with an access count of 1. Consider a situation of using lockers in the bank. Usually the rule is that only one person is allowed to enter the locker room.
References
http://www.geeksforgeeks.org/semaphore-in-java/
https://www.mkyong.com/java/java-thread-mutex-and-semaphore-example/



No comments:

Post a Comment