Tuesday, 8 April 2014

How to avoid thread collision using Locks in java?

Each of the method discussed here  has some advantages and disadvantages.  Here we will see the java.util.concurrent.locks  package.

java.util.concurrent.locks package:

The java API says this packages as, 'Interfaces and classes providing a framework for locking and waiting for conditions that is distinct from built-in synchronization and monitors.'

This package has the following main classes.

  • AbstractOwnableSynchronizer
  • AbstractQueuedLongSynchronizer
  • AbstractQueuedSynchronizer
  • LockSupport
  • ReentrantLock
  • ReentrantReadWriteLock
  • ReentrantReadWriteLock.ReadLock
  • ReentrantReadWriteLock.WriteLock

Example

Remember the race condition example, which we discussed earlier. The same program with ReentrantLock, will solves the race condition. Please see the below code.
package thread;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Sivaranjani D
 * 
 */
public class AccountOverDraw{

 public static void main(String[] args) {
  Runnable atm = new ATM();
  Thread withdrwer1 = new Thread(atm);
  withdrwer1.setName("withdrawer1");
  withdrwer1.start();

  Thread withdrwer2 = new Thread(atm);
  withdrwer2.setName("withdrawer2");
  withdrwer2.start();
 }

}

class Account {
 int balance = 500;

 public void debit(int amount) {
  balance = balance - amount;
 }

 public void credit(int amount) {
  balance = balance + amount;
 }

 public int getBalance() {
  return balance;
 }
}

class ATM implements Runnable {
 Account account = new Account();
 Lock lock = new ReentrantLock();
 public void run() {
   for (int i = 0; i <10; i++) {
    lock.lock();
   if (account.getBalance() > 0) {
    makeWithdrawal(100);
   } else {
    System.out.println("Not enough in amount for "
      + Thread.currentThread().getName() + " to withdraw ");
   }
   lock.unlock();
  } 
 }

 private  void makeWithdrawal(int amt) {
  if (account.getBalance() >= amt) {
   System.out.println(Thread.currentThread().getName()
     + " cheked balance and the balance is :"
     + account.getBalance());

   account.debit(amt);
   System.out.println(Thread.currentThread().getName()
     + " completes the withdrawal and the balance: "
     + account.getBalance());
  }
 }

}

Explanation:

  1. The only difference which avoids race condition is, here the atomic statements are wrapped inside the lock and unlock.
  2. This step ensures that both the statements can be accessed by only one thread at a time. Also if one thread does balance check it does the debit as well before the other thread reads the balance.

No comments:

Post a Comment