Wednesday, August 9, 2017

Lock Interface , another way of thread communication

REENTRANT LOCK AND LOCK INTERFACE IN JAVA

ReentrantLock extends functionality of synchronized keyword
in Java and open path for more controlled locking in Java. 
Lock is acquired by lock() method and held by Thread until a call to unlock() method. Fairness  parameter is provided while creating instance of ReentrantLock in constructor. ReentrantLock provides same visibility and ordering guarantee, provided by implicitly locking, which means, unlock() happens before another thread get lock().

Lock - Base interface for Lock API:
It provides all the features of synchronized keyword with additional ways to create different Conditions for locking, providing timeout for thread to wait for lock. Some of the important methods are lock() to acquire the lock, unlock() to release the lock, tryLock() to wait for lock for a certain period of time, newCondition() to create the Condition etc.

Definition
A lock is a tool for controlling access to a shared resource by multiple threads. Commonly, a lock provides exclusive access to a shared resource: only one thread at a time can acquire the lock and all access to the shared resource requires that the lock be acquired first. However, some locks may allow concurrent access to a shared resource, such as the read lock of a {@link ReadWriteLock}.

  Lock l = ...;
   l.lock();
   try {
    // access the resource protected by this lock
  } finally {
    l.unlock();
  }}</pre>

When locking and unlocking occur in different scopes, care must be taken to ensure that all code that is executed while the lock is held is protected by try-finally or try-catch to ensure that the lock is released when necessary.

Lock implementations provide additional functionality
over the use of {@code synchronized} methods and statements by
providing a non-blocking attempt to acquire a lock ({@link
#tryLock()}), an attempt to acquire the lock that can be
interrupted ({@link #lockInterruptibly}, and an attempt to acquire the lock that can timeout ({@link #tryLock(long, TimeUnit)}).

interface Lock
void lock();
Acquires the lock.
If the lock is not available then the current thread becomes
disabled for thread scheduling purposes and lies dormant until the
lock has been acquired.

void lockInterruptibly() throws InterruptedException;
Acquires the lock unless the current thread is interrupted.
Acquires the lock if it is not held by another thread and returns immediately, setting the lock hold count to one.
If the current thread already holds this lock then the hold count is incremented by one and the method returns immediately.
If the lock is held by another thread then the current thread becomes disabled for thread scheduling purposes and lies dormant until one of two things happens:

boolean tryLock();
Acquires the lock if it is available and returns immediately
with the value {@code true}.
If the lock is not available then this method will return
immediately with the value {@code false}.

boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Releases the lock
Condition newCondition();

Below code explains usage of LOCK API in java . Same can be achieved using synchronized block as well.

public class ReentrantLockImpl {

     private final ReentrantLock lock = new ReentrantLock();
     private int count = 0;

     /* Locking using Lock and ReentrantLock */
     public int incrementCount() {
          lock.lock();
          try {
              System.out.println(Thread.currentThread().getName() + " gets Count: " + count);
              return count++;
          } finally {
              lock.unlock();
          }
     }

     public static void main(String args[]) {
          final ReentrantLockImpl counter = new ReentrantLockImpl();
          Thread t1 = new Thread() {

              @Override
              public void run() {
                   while (counter.incrementCount() < 10) {
                        try {
                             Thread.sleep(100);
                        } catch (InterruptedException ex) {
                             ex.printStackTrace();
                        }
                   }
              }
          };

          Thread t2 = new Thread() {

              @Override
              public void run() {
                   while (counter.incrementCount() < 10) {
                        try {
                             Thread.sleep(100);
                        } catch (InterruptedException ex) {
                             ex.printStackTrace();
                        }
                   }
              }
          };

          t1.start();
          t2.start();
     }
}

Output

Thread-0 gets Count: 0
Thread-1 gets Count: 1
Thread-1 gets Count: 2
Thread-0 gets Count: 3
Thread-0 gets Count: 4
Thread-1 gets Count: 5
Thread-1 gets Count: 6
Thread-0 gets Count: 7
Thread-0 gets Count: 8
Thread-1 gets Count: 9
Thread-1 gets Count: 10
Thread-0 gets Count: 11

References



No comments:

Post a Comment