Java Multi threaded programming basics with Reentrant locks
As we have seen in earlier post that implicit locking mechanism achieved using synchronized keyword slows down the application performance. Hence java concurrency api gives explicit locking mechanism to achieve mutual exclusion among shared object.How using explicit locks are better than implicit lock?
- Explicit lock acquires lock per Thread basis and not per method invoke basis. It is inverse in the case of implicit lock.
- If a method is synchronized then every invocation of that method involves acquiring and releasing of lock. This process really slows down the application performance.
- Hence it is always good idea to prefer reentrent lock or explicit lock to implicit lock.
- ReentrantLock is a class available in java.util.concurrency package
- lock() and unlock() methods are used used to acquire and release the lock.
- Condition class is used in place of Object class wait(), notifyAll() and notify().
- signal() and await() of Condtion are used mostly
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
 * In {@code BufferImpl} we have seen thread safe 
 * buffer implementation using implicit lock/ synchronization block * 
 * This {@code BufferImpl_conc} we see same implementation replacing implicit
 * lock with concurrency utility classes Reentrant Locks
 * 
 * Buffer implementation with ArrayList and with Producer consumer 
 * problem implementation
 * 
 * @author Nagasharath
 *
 */
public class BufferImpl_conc {
   private CopyOnWriteArrayList<String> buffer;
   private final short SIZE = 10;
   private boolean isBufferFull = false;
   private ReentrantLock lock;
   private Condition condition;
  public BufferImpl_conc() {
     buffer = new CopyOnWriteArrayList<String>();
     lock = new ReentrantLock();
     condition = lock.newCondition();
  }
 /**
  * @throws InterruptedException
  */
 private void producesFeed() throws InterruptedException {
    lock.lock();
    try {
       while (true) {
         if (isBufferFull) {
             System.out.println("Started Consuming!....\n");
             condition.signal();
             condition.await();
        }
        buffer.add(String.valueOf(System.nanoTime()));
        if (SIZE <= buffer.size()) {
              isBufferFull = true;
              Thread.sleep(10000);
              System.out.println("Buffer full. Production halts...\n");
       }
     }
    } finally {
        lock.unlock();
    }
 }
 /**
  * @throws InterruptedException
  */
 private void consumesFeed() throws InterruptedException {
    lock.lock();
    try {
       while (true) {
          Iterator<String> iter = buffer.iterator();
          while (iter.hasNext()) {
             String next = iter.next();
             System.out.println("Consuming element: " + next);
             buffer.remove(buffer.indexOf(next));
          }
          isBufferFull = false;
          System.out.println("Started producing!....");
          condition.signal();
          condition.await();
      }
   } finally {
      lock.unlock();
   }
 }
 /**
  * @author Nagasharath
  *
  */
 class ProducerThread extends Thread {
     @Override
    public void run() {
      try {
        producesFeed();
      } catch (InterruptedException e) {
      }
  }
 }
 /**
  * @author Nagasharath
  *
  */
 class ConsumerThread extends Thread {
  @Override
  public void run() {
    try {
      consumesFeed();
    } catch (InterruptedException e) {
    }
  }
 }
 public static void main(String[] args) {
   BufferImpl_conc impl = new BufferImpl_conc();
   ProducerThread producerThread = impl.new ProducerThread();
   ConsumerThread consumerThread = impl.new ConsumerThread();
   producerThread.start();
   consumerThread.start();
 }
}
  1 private final short SIZE = 10;  2 private boolean isBufferFull = false;  3 private ReentrantLock lock;  4 private Condition condition;Line 3: Instance of ReentrantLock is similar to synchronized keyword locking but it is more intelligent.
Line 4: Condition instance has methods which replaces Object class wait and notify() methods.
  1  public BufferImpl_conc() {  2     buffer = new CopyOnWriteArrayList<String>();  3     lock = new ReentrantLock();  4     condition = lock.newCondition();  5  } 1 private void producesFeed() throws InterruptedException { 2   lock.lock(); 3    try { 4      while (true) { 5         if (isBufferFull) { 6             System.out.println("Started Consuming!....\n"); 7             condition.signal(); 8             condition.await(); 9         } 10         buffer.add(String.valueOf(System.nanoTime())); 11         if (SIZE <= buffer.size()) { 12           isBufferFull = true; 13           Thread.sleep(10000); 14           System.out.println("Buffer full. Production halts...\n"); 15         } 16       } 17     } finally { 18          lock.unlock(); 19     } 20 }Line 2: lock.lock() statement is equal to the synchronized(this) { . . . }
Line 7: condition.signal() notifies the waiting thread on same object to start it's execution
Line 8: condition.await() makes current thread to wait on isBufferFull == true condition check
Line 17 to Line 19: lock.unlock() must be called in finally block always
Output:
Buffer full. Production halts...Started Consuming!....Consuming element: 2838231927112595Consuming element: 2838231927212435Consuming element: 2838231927229502Consuming element: 2838231927238888Consuming element: 2838231927246995Consuming element: 2838231927254675Consuming element: 2838231927261075Consuming element: 2838231927267902Consuming element: 2838231927274302Consuming element: 2838231927281555Started producing!....Buffer full. Production halts...Started Consuming!....Consuming element: 2838242029132348Consuming element: 2838242029210428Consuming element: 2838242029244561Consuming element: 2838242029271015Consuming element: 2838242029386215Consuming element: 2838242029448935Consuming element: 2838242029479228Consuming element: 2838242029504401Consuming element: 2838242029529148Consuming element: 2838242029553895Started producing!....Buffer full. Production halts...Started Consuming!....Consuming element: 2838252029524881Consuming element: 2838252029547921Consuming element: 2838252029556881Consuming element: 2838252029563281Consuming element: 2838252029568401Consuming element: 2838252029573521Consuming element: 2838252029578215Consuming element: 2838252029582908Consuming element: 2838252029588028Consuming element: 2838252029593148Started producing!....Buffer full. Production halts...Started Consuming!....Consuming element: 2838262032106639Consuming element: 2838262032149732Consuming element: 2838262032165092Consuming element: 2838262032193252Consuming element: 2838262032204772Consuming element: 2838262032214585Consuming element: 2838262032223972Consuming element: 2838262032233359Consuming element: 2838262032241892Consuming element: 2838262032251279Started producing!....Buffer full. Production halts...Started Consuming!....Consuming element: 2838272040024285Consuming element: 2838272040065245Consuming element: 2838272040077619Consuming element: 2838272040086152Consuming element: 2838272040093832Consuming element: 2838272040101512Consuming element: 2838272040108766Consuming element: 2838272040115592Consuming element: 2838272040122845Consuming element: 2838272040130099Started producing!.... 
 
 
 
 
 
 
No comments:
Post a Comment