Overview
Lock API in Java is a more flexible and easy way for achieving the synchronization mechanism over the traditional use of synchronized keyword.
Lock API was introduced in java 1.5 release. It is defined inside the java.util.concurrent.lock package.
This tool for controlling access to a shared resource by multiple threads. In multithreaded programs, access to shared variables must be synchronizedΒ to prevent race conditions.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 ReadWriteLock.
Difference Between Lock and synchronized block
A synchronized block does not provide fairness to the multiple threads because any thread can acquire the object lock once previous existing lock is released
We can achieve fairness within the Lock APIs by specifying the fairness property. It makes sure that longest waiting thread is given access to the lock.
A thread gets blocked if it canβt get an access to the synchronized block. The Lock API provides tryLock() method.
The thread acquires lock only if itβs available and not held by any other thread. This reduces blocking time of thread waiting for the lock.
A thread which is in βwaitingβ state to acquire the access to synchronized block, canβt be interrupted. The Lock API provides a method lockInterruptibly()
which can be used to interrupt the thread when itβs waiting for the lock
we can have Java Lock APIβs lock() and unlock() operation in separate methods
Object monitor lock acquired through synchronized block is released automatically once its execution of block or method is completed. But in case of Lock api in java, lock needs to be released explicitly.
Lock API
Let us have a look at the methods of the Lock interface:
- void lock() β acquire the lock if itβs available; if the lock isnβt available a thread gets blocked until the lock is released.
- void lockInterruptibly() β this is similar to the lock(), but it allows the blocked thread to be interrupted and resume the execution through a thrown java.lang.InterruptedException
- boolean tryLock() β this is a non-blocking version of lock() method; it attempts to acquire the lock immediately, return true if locking succeeds
- boolean tryLock(long timeout, TimeUnit timeUnit) β this is similar to tryLock(), except it waits up the given timeout before giving up trying to acquire the Lock
- void unlock() β unlocks the Lock instance
- A locked instance should always be unlocked to avoid deadlock condition.
Sample Code block which uses Lock API in Java:
Lock lock = …; lock.lock();
try {
// access to the shared resource
}
finally {
lock.unlock();
}
In addition to the Lock API in java , we have a ReadWriteLock interface which maintains a pair of locks, one for read-only operations,
and one for the write operation. The read lock may be simultaneously held by multiple threads as long as there is no write.
ReadWriteLock declares methods to acquire read or write locks:
Lock readLock() β returns the lock and used for reading
Lock writeLock() β returns the lock and used for writing
1. ReentrantLock
ReentrantLockΒ class implements theΒ LockΒ interface. It offers the same concurrency and memory semantics as the implicit monitor lock used usingΒ synchronizedΒ methods and statements, with more capabilities.
public class SharedClass { ReentrantLock lock = new ReentrantLock(); int counter = 0; public void doLock() { lock.lock(); try { // Important code here count++; } finally { lock.unlock(); } } }
Note: wrap theΒ lock() and theΒ unlock()Β calls in theΒ try-finallyΒ block to avoid the deadlock situations.
Letβs see how theΒ tryLock()Β works:
TheΒ tryLock()
Β method tries to acquire the lock without pausing the thread. That is, If the thread couldnβt acquire the lock because it was held by some other thread, then It returns immediately instead of waiting for the lock to be released.
You can also specify a timeout in theΒ tryLock()
Β method to wait for the lock to be available –
lock.tryLock(1, TimeUnit.SECONDS);
public void doTryLock(){ boolean isLockAcquired = lock.tryLock(1, TimeUnit.SECONDS); if(isLockAcquired) { try { } finally { lock.unlock(); } } }
2. ReadWriteLock
ReadWriteLock consists of a pair of locks – one for read access and one for write access. The read lock may be held by multiple threads simultaneously as long as the write lock is not held by any thread.
ReentrantReadWriteLockΒ class implements theΒ ReadWriteLockΒ interface.
Letβs see rules for acquiring theΒ ReadLockΒ orΒ WriteLockΒ by a thread:
- Read LockΒ β if no thread acquired the write lock or requested for it then multiple threads can acquire the read lock
- Write LockΒ β if no threads are reading or writing then only one thread can acquire the write lock
Letβs see how to make use of theΒ ReadWriteLock:
public class HashMapWithReadWriteLock { Map<String,String> sHashMap = new HashMap<>(); ReadWriteLock lock = new ReentrantReadWriteLock(); Lock writeLock = lock.writeLock(); public void put(String key, String value) { try { writeLock.lock(); sHashMap.put(key, value); } finally { writeLock.unlock(); } } public String remove(String key){ try { writeLock.lock(); return sHashMap.remove(key); } finally { writeLock.unlock(); } } }
I hope you understood well about Lock API. Thanks…
This is truly useful, thanks.
Thanks Rosalinda. Keep reading our articles and subscribe our blogs