Saturday, November 6, 2010

The Lock API

The Java 5.0 comes with new features in the concurrency package to take care of the locking strategy. The previous locking in Java 2.0 had a lot of disadvantages, like once a thread is waiting for a lock its not possible to interrupt it. Also the thread will wait for ever if its not able to acquire the lock. The order of acquiring the lock is also dependent on the thread scheduler and there is no way we can force the scheduler to give a prticular thread more priority in acquiring a lock. Intrinsic lock also needs to be released in the same block in which it acquires the lock.

All the above problems has been answered in the updates in Java 5.0 with the advent of the Lock package. We can acquire a lock equivalent to a synchronized block by using the lock() method in the ReentrantLock class. The example of Blocking Queue with wait() notify() can be rewritten with the lock strategy.

public class BlockingQueue5 extends BlockingQueue {
 
   private Queue queue = new LinkedList();
     String testingwait = new String();
     Lock lock = new ReentrantLock();
     Condition notFull = lock.newCondition();
     Condition notEmpty = lock.newCondition();
     private int capacity;

     public BlockingQueue5(int capacity) {
      super(capacity);
         this.capacity = capacity;
     }

     public void put(T element) throws InterruptedException {
      lock.lock();
         try {
    while(queue.size() == capacity) {
     
     notFull.await();
        
    }
    
    queue.add(element);
    notEmpty.signal();
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }finally{
    lock.unlock();
   }
     }

     public T take() throws InterruptedException {
      lock.lock();
         try {
    while(queue.isEmpty()) {
     
        notEmpty.await();
        
    }
    
    T item = queue.remove();
    notFull.signal();
    return item;
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }finally{
    lock.unlock();
   }
   return null;
     }

}

As can be seen the synchronized has been replaced by the lock(). Before any task is started the lock should be acquired . Its also imperative that the lock should be released come what may, so its essential that the release section should be in a  finally block. The wait and notify has been replaced by the Condition object. The await () and the signal()  methods  are equivalent to wait and notify. It necessary that the condition on which the await has been called , the signal is also called on the same condition.

Another method in the Lock class is the tryLock(). It solves the problems of deadlocking as seen in Dead Lock situation. The tryLock also comes with a overloaded method which takes in nanoseconds as parameters       which means the number of nano secs it will wait to acquire a lock after which it can resume with other operations. The tryLock acquires the lock if no other thread is waiting on that lock and in a thread ordering situation it gets the first preference. The  TransactionTryLock class below replaces the Transaction class and shows how tryLock can avoid deadlock situation.
public class TransactionTryLock extends Transaction{
 
 
private Lock accountA = new ReentrantLock();
private Lock accountB = new ReentrantLock();

public void transferA2B(){
 if(accountA.tryLock()) {
  System.out.println("lock for A held in A2B");
  try {
   // sleep given to force deadlock
   Thread.sleep(1000);
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  
  if(accountB.tryLock()) {
   System.out.println("lock for B held in A2B");
   
  }

 }
}

public void transferB2A(){
 if(accountB.tryLock()) {
  System.out.println("lock for B held in B2A");
  try {
   // sleep given to force deadlock
   Thread.sleep(1000);
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  if(accountA.tryLock()) {
   
   System.out.println("lock for A held in B2A");
   
  }

 }
}

}

No comments:

Post a Comment