Last active
March 17, 2018 08:50
-
-
Save vikasverma787/9acfb081c4f4364b8100557635cc6178 to your computer and use it in GitHub Desktop.
Java Lock Example Reentrant Lock
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Lock : This is the 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. methods are lock(),unlock(),tryLock(),newCondition() | |
Condition: Condition objects are similar to Object wait-notify model with additional feature to create different sets of wait. | |
A Condition object is always created by Lock object. Some of the important methods are await() that is similar to wait() and signal(), | |
signalAll() that is similar to notify() and notifyAll() methods. | |
Benefits : | |
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. | |
synchronized keyword doesn’t provide fairness whereas we can set fairness to true while creating ReentrantLock object so that longest waiting | |
thread gets the lock first. | |
One more worth noting difference between ReentrantLock and synchronized keyword in Java is, ability to interrupt Thread while waiting for | |
Lock. In case of synchronized keyword, a thread can be blocked waiting for lock, for an indefinite period of time and there was no way to | |
control that. ReentrantLock provides a method called lockInterruptibly(), which can be used to interrupt thread when it is waiting for lock. | |
Similarly tryLock() with timeout can be used to timeout if lock is not available in certain time period. | |
4) ReentrantLock also provides convenient method to get List of all threads waiting for lock. | |
tryLock/timeout for waiting for Lock/lock interrutibility/lock fairness/ get the no of threads watining for lock. | |
public class ReentrantLockHowto { | |
private final ReentrantLock lock = new ReentrantLock(); | |
private int count = 0; | |
// Locking using Lock and ReentrantLock | |
public int getCount() { | |
lock.lock(); | |
try { | |
System.out.println(Thread.currentThread().getName() + " gets Count: " + count); | |
return count++; | |
} finally { | |
lock.unlock(); | |
} | |
} | |
// Implicit locking using synchronized keyword | |
public synchronized int getCountTwo() { | |
return count++; | |
} | |
public static void main(String args[]) { | |
final ReentrantLockHowto counter = new ReentrantLockHowto(); | |
Thread t1 = new Thread() { | |
@Override | |
public void run() { | |
while (counter.getCount() < 6) { | |
try { | |
Thread.sleep(100); | |
} catch (InterruptedException ex) { | |
ex.printStackTrace(); | |
} | |
} | |
} | |
}; | |
Thread t2 = new Thread() { | |
@Override | |
public void run() { | |
while (counter.getCount() < 6) { | |
try { | |
Thread.sleep(100); | |
} catch (InterruptedException ex) { | |
ex.printStackTrace(); | |
} | |
} | |
} | |
}; | |
t1.start(); | |
t2.start(); | |
} | |
} | |
Locks In Synchronized Methods : | |
When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it | |
when the method returns. The lock release occurs even if the return was caused by an uncaught exception. | |
Let’s see how the tryLock() works: | |
public void performTryLock(){ | |
//... | |
boolean isLockAcquired = lock.tryLock(1, TimeUnit.SECONDS); | |
if(isLockAcquired) { | |
try { | |
//Critical section here | |
} finally { | |
lock.unlock(); | |
} | |
} | |
//... | |
} | |
In this case, the thread calling tryLock(), will wait for one second and will give up waiting if the lock is not available. | |
ReentrantReadWriteLock | |
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: | |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
public class SynchronizedHashMapWithReadWriteLock { | |
Map<String,String> syncHashMap = new HashMap<>(); | |
ReadWriteLock lock = new ReentrantReadWriteLock(); | |
//... | |
Lock writeLock = lock.writeLock(); | |
public void put(String key, String value) { | |
try { | |
writeLock.lock(); | |
syncHashMap.put(key, value); | |
} finally { | |
writeLock.unlock(); | |
} | |
} | |
... | |
public String remove(String key){ | |
try { | |
writeLock.lock(); | |
return syncHashMap.remove(key); | |
} finally { | |
writeLock.unlock(); | |
} | |
} | |
//... | |
} | |
For both the write methods, we need to surround the critical section with the write lock, only one thread can get access to it: | |
Lock readLock = lock.readLock(); | |
//... | |
public String get(String key){ | |
try { | |
readLock.lock(); | |
return syncHashMap.get(key); | |
} finally { | |
readLock.unlock(); | |
} | |
} | |
public boolean containsKey(String key) { | |
try { | |
readLock.lock(); | |
return syncHashMap.containsKey(key); | |
} finally { | |
readLock.unlock(); | |
} | |
} | |
For both read methods, we need to surround the critical section with the read lock. Multiple threads can get access to this section if no | |
write operation is in progress. | |
Working with Conditions: | |
public class ReentrantLockWithCondition { | |
Stack<String> stack = new Stack<>(); | |
int CAPACITY = 5; | |
ReentrantLock lock = new ReentrantLock(); | |
Condition stackEmptyCondition = lock.newCondition(); | |
Condition stackFullCondition = lock.newCondition(); | |
public void pushToStack(String item){ | |
try { | |
lock.lock(); | |
while(stack.size() == CAPACITY){ | |
stackFullCondition.await(); | |
} | |
stack.push(item); | |
stackEmptyCondition.signalAll(); | |
} finally { | |
lock.unlock(); | |
} | |
} | |
public String popFromStack() { | |
try { | |
lock.lock(); | |
while(stack.size() == 0){ | |
stackEmptyCondition.await(); | |
} | |
return stack.pop(); | |
} finally { | |
stackFullCondition.signalAll(); | |
lock.unlock(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment