What are Reentrant Locks?
- ReentrantLock in Java is added on java.util.concurrent package in Java 1.5 along with other concurrent utilities like CountDownLatch, Executors, and CyclicBarrier.
- ReentrantLock is a concrete implementation of the Lock interface provided in the Java concurrency package from Java 1.5 onwards.
- Reentrant Locks are provided in Java to provide synchronization with greater flexibility.
- The code which manipulates the shared resource is surrounded by the calls to lock and unlock method. This gives a lock to the current working thread and blocks all other threads which are trying to take a lock on the shared resource.
- A ReentrantLock allows threads to enter into the lock on a resource more than once. When the thread first enters into the lock, a hold count is set to one. Before unlocking the thread can re-enter into lock again and every time hold count is incremented by one. For every un-lock request, the hold count is decremented by one and when the hold count is 0, the resource is unlocked.
- Fairness parameter is provided while creating an instance of ReentrantLock in the constructor. The fairness parameter used to construct the lock object decreases the throughput of the program.
- ReentrantLock provides the same visibility and ordering guarantee, provided by implicitly locking, which means, unlock() happens before another thread gets lock().
- If you forget to call the unlock() method in the finally block, it will lead to bugs in the program. Make sure that the lock is released before the thread exits.
Difference between ReentrantLock and synchronized keyword in Java
- We can achieve thread synchronization in Java by using the 'synchronized' keyword. While it provides a certain basic synchronization, the synchronized keyword is quite rigid in its use. e.g, a thread can take a lock only once. Synchronized blocks don’t offer any mechanism of a waiting queue and after the exit of one thread, any thread can take the lock. This could lead to starvation of resources for some other thread for a very long period of time. ReentrantLock provides a method called lockInterruptibly(), which can be used to interrupt a thread when it is waiting for the lock. Similarly, tryLock() with timeout can be used to timeout if the lock is not available in a certain time period.
- Fairness property provides a lock to the longest waiting thread, in case of contention. the synchronized keyword doesn't support fairness. Any thread can acquire a lock once released, no preference can be specified. In ReentrantLock we can specify the fairness property while creating an instance of ReentrantLock.
- ReentrantLock provides a convenient tryLock() method, which acquires a lock only if it's available or not held by any other thread. This reduces the blocking of threads waiting for a lock-in Java application. This is not possible in the case of a synchronized keyword.
- ReentrantLock also provides a convenient method to get a list of all threads waiting for the lock. We can create different conditions for Lock and different threads can await() for different conditions.
- Synchronization code is much cleaner and easy to maintain whereas with Lock we are forced to have a try-finally block to make sure Lock is released even if some exception is thrown between lock() and unlock() method calls.
- synchronization blocks or methods can cover only one method whereas we can acquire the lock in one method and release it in another method with Lock API.
What is a Read-Write Lock? Does ConcurrentHashMap in Java Use The ReadWrite Lock?
ReadWrite Lock is an implementation of a lock stripping technique, where two separate locks are used for reading and writing operations. Since the read operation doesn't modify the state of the object, it's safe to allow multiple thread access to a shared object for reading without locking, and by splitting one lock into the read and write lock, you can easily do that.
Java provides an implementation of a read-write lock in the form of the ReentrantReadWriteLock class in the java.util.concurrent.lock package.
The current implementation of java.util.ConcurrentHashMap doesn't use the ReadWriteLock, instead, it divides the Map into several segments and locks them separately using different locks. This means any given time, only a portion of the ConcurrentHashMap is locked, instead of the whole Map.
How ReentrantReadWriteLock work internally?
A java.util.concurrent.locks.ReadWriteLock is an advanced thread lock mechanism. It allows multiple threads to read a certain resource, but only one to write it, at a time. The multiple threads can read from a shared resource without causing concurrency errors.
ReadWriteLock Locking Rules
- Read Lock: If no threads have locked the ReadWriteLock for writing, and no thread has requested a write lock (but not yet obtained it). Thus, multiple threads can lock the lock for reading.
- Write Lock: If no threads are reading or writing. Thus, only one thread at a time can lock the lock for writing.
ReadWriteLock is an interface, ReentrantReadWriteLock provide its implementation.
ReadLock and WriteLock are the static nested classes with in the ReentrantReadWriteLock class:
- ReentrantReadWriteLock.ReadLock– The lock returned by method ReadWriteLock.readLock().
- ReentrantReadWriteLock.WriteLock– The lock returned by method ReadWriteLock.writeLock().
ReentrantReadWriteLock follows the same convention as followed by ReentrantLock in Java where the call to lock() method is placed before the try block and then followed with a try-finally or try-catch-finally block and uses the finally block to call unlock() method. That way unlock() method is called only if the lock is actually acquired and it is also ensured that the unlock() method is called if there is any error after the lock is acquired.
ReentrantReadWriteLock Properties
- There is no reader or writer preference ordering for lock access. However, it does support an optional fairness policy.
- When ReentrantReadWriteLock is constructed as non-fair, which is the default, the order of entry to the read and write lock is unspecified.
- When ReentrantReadWriteLock is constructed as fair, threads contend for entry using an approximately arrival-order policy. When the currently held lock is released, either the longest-waiting single writer thread will be assigned the write lock, or if there is a group of reader threads waiting longer than all waiting writer threads, that group will be assigned the read lock.
- Both read and write locks can reacquire read or write locks in the style of a ReentrantLock.
- Reentrancy also allows downgrading from the write lock to a read lock, by acquiring the write lock, then the read lock and then releasing the write lock.
- Upgrading from a read lock to the write lock is not possible.
What do you understand by Reentrant Synchronization in Java programming language?
A thread cannot acquire a lock that is held by another thread. But a thread can acquire a lock that it already owns. This happens when a synchronized code calls a method that itself has synchronized code, and both sets of code use the same code.
No comments:
Post a Comment