Lock & Condition
Difference between intrinsic (synch, wait(), notify()) and explicit locking (using lock, semaphores):
- explicit locks provide interruptability, timeouts, fairness.
Reentrant lock: when a thread holds a lock, it can enter a block synchronized on the lock it is holding.
Calling unlock() from a finally clause.
lock.lock();
try{
//do something in critical region which may throw Exception
} finally {
lock.unlock();
}
Lock Reentrance
We need to count the number of times the lock has been locked by the same thread. Otherwise, a single call tounlock()
will unlock the lock, even if the lock has been locked multiple times.
public class Lock{
boolean isLocked = false;
Thread lockedBy = null;
int lockedCount = 0;
public synchronized void lock()
throws InterruptedException{
Thread callingThread = Thread.currentThread();
while(isLocked && lockedBy != callingThread){
wait();
}
isLocked = true;
lockedCount++;
lockedBy = callingThread;
}
public synchronized void unlock(){
if(Thread.curentThread() == this.lockedBy){
lockedCount--;
if(lockedCount == 0){
isLocked = false;
notify();
}
}
}
...
}
ReadWrite Lock
http://tutorials.jenkov.com/java-concurrency/read-write-locks.html
ReadWriteLock in java concurrent library
private ReadWriteLock lock = new ReentrantReadWriteLock(true);
private Lock readLock = lock.readLock();
private Lock writeLock = lock.writeLock();
public String put(Long key, String value) {
writeLock.lock();
try {
return cache.put(key, value);
} finally {
writeLock.unlock();
}
}
public String get(Long key) {
readLock.lock();
try {
return cache.get(key);
} finally {
readLock.unlock();
}
}
Semaphore
Possible implementation:
public class BoundedSemaphore {
private int signals = 0;
private int bound = 0;
public BoundedSemaphore(int upperBound){
this.bound = upperBound;
}
public synchronized void take() throws InterruptedException{
while(this.signals == bound) wait();
this.signals++;
this.notify();
}
public synchronized void release() throws InterruptedException{
while(this.signals == 0) wait();
this.signals--;
this.notify();
}
}
It is possible to use a bounded semaphore as a lock to limit the number of threads allowed into a section of code.
Semaphore semaphore = new Semaphore(5);
try {
//semaphore.acquire();
if(semaphore.tryAcquire()) {
//guarded block of code
} else {
}
} finally {
semaphore.release();
}
Condition
- Condition factors out the Object monitor methods (wait, notify and notifyAll) into distinct objects to give the effect of having multiple wait-sets per object.
- Where a Lock replaces the use of synchronized methods and statements, a Condition replaces the use of the Object monitor methods.
- Because access to this shared state information occurs in different threads, it must be protected, so a lock of some form is associated with the condition.
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();