Wednesday, July 7, 2010

Few Multi-Threading Implementations


Sequential Producer & Consumer
In my first example, I will demonstrate an implementation to solve the famous producer and consumer problem. Producer should complete its production, before Consumer can consume it, as simple as that. In addition, both the operations should run on 2 separate threads.
public class SequentialExecutor {

      /**
       * Shared
       */
      volatile int shared;
     
      /**
       * Lock object, whose monitor will be shared by both the threads
       */
      Object lock = new Object();
     
      /**
       * Producer
       */
      P p;
     
      /**
       * Consumer
       */
      C c;
     
      public SequentialExecutor(){
            p = new P();
            c = new C();
      }
     
      public class P implements Runnable {
            public void run(){
                  while(true){
                        synchronized (lock) {
                              try{
                                    // add some processing delay
                                    Thread.sleep(1000);
                              }catch(Exception ex){
                                    ex.printStackTrace();
                              }
                              shared++;
                              System.out.println("Produce->"+ shared);
                        }
                  }
            }
      }
     
      public class C implements Runnable {
            public void run(){
                  while(true){
                        synchronized (lock) {
                              try{
                                    // add some processing delay
                                    Thread.sleep(1500);
                              }catch(Exception ex){
                                    ex.printStackTrace();
                              }
                              System.out.println("Consume->"+ shared);
                        }
                  }
            }
      }
     
      public static void main(String[] args){
            SequentialExecutor se = new SequentialExecutor();
            new Thread(se.p, "P Thread").start();
            new Thread(se.c, "C Thread").start();
      }
}
You’ll get output as-
Produce->1
Consume->1
Produce->2
Consume->2
Produce->3
Consume->3
Produce->4
Consume->4
Here the trick is being done by the common object lock.

Binary Semaphore Implementation
public class Semaphore {

      int counter = 0;
      /**
       * Binary Semaphore- restricts the probable counter values
       * to (0/1)
       */
      int BOUND = 1;
     
      /**
       * Acquire the lock.
       * This SHOULD be an Atomic operation
       */
      public synchronized void acquire(){
            Thread currentThread = Thread.currentThread();
            System.out.println("[acquire] Thread: "+ currentThread.getName()+" - Start");
            System.out.println("Counter: "+ counter);
           
            while(counter == BOUND){
                  // make the calling  thread wait
                  System.out.println(currentThread.getName()+ " Waiting to Acquire...");
                  try{
                        wait();
                  }catch(Exception ex){
                        ex.printStackTrace();
                  }
            }
            counter++;
            System.out.println("[acquire] Thread: "+ currentThread.getName()+" -Done");
      }
     
      /**
       * Release the lock.
       * This SHOULD be an Atomic operation
       */
      public synchronized void release(){
            Thread currentThread = Thread.currentThread();
            System.out.println("[release] Thread: "+ currentThread.getName());
            System.out.println("Counter: "+ counter);
           
            if(counter > 0){
                  counter--;
                  try{
                        // Notify the other thread waiting to acquire lock
                        notify();
                  }catch(Exception ex){
                        ex.printStackTrace();
                  }
            }
      }
}
How to use it-
  1. Acquire the Semaphore lock- acquire()
  2. Do some operation.
  3. Release the Semaphore lock. (Make sure you release it. Otherwise, other threads will never get chance to execute)- release()

No comments:

Post a Comment