What is the use of Condition along with Lock in Java - java

I am trying to understand what is the use of doing condition.await() if I am already doing lock.lock()
If I understood locks correctly, once I do lock.lock() it will not proceed any further if some other thread has a lock.
So, in this case if pushToStack() has acquired a lock by doing lock.lock() then what is the use of checking for stackEmptyCondition.await() in the popFromStack() method? Because anyway, the code will stop at the lock.lock() line in the popFromStack() method. What am I missing/wrong?
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(); // we are blocked here to acquire a lock
while(stack.size() == 0) {
stackEmptyCondition.await(); // then why do we need to check this again?
}
return stack.pop();
} finally {
stackFullCondition.signalAll();
lock.unlock();
}
}
}

The point is the Condition, not the Lock.
It is often the case that a program needs to wait until either "something happens" or "something is in a particular state". The Condition represents what you're waiting for.
In order to program such a thing safely, some sort of locking is needed. If you're waiting for something to be in a particular state, you really want it to remain in that state while you do whatever you had in mind when you decided to wait for it. That's where the Lock comes in.
In your example, you want to wait until the stack is not full, and when you discover that the stack is not full, you want it to stay not-full (that is, prevent some other thread from pushing on to the stack) while you push something on that stack.

Related

Object vs Condition, wait() vs await()

In the solution to an programming exercise concerning locks, I've noticed they were using an Object to syncronize on, so something like:
Lock lock = new ReentrantLock();
Object obj = new Object();
and in a method:
synchronized(obj){
obj.wait();}
my question is, could I have used a Condition instead, let's say:
Condition cond = lock.newCondition();
and then use, in the method,
cond.await()
instead, without putting it in a synhronized block?
edit: the solution:
How would I implement this with the Condition?
Yes. But you have to aquire the lock first. See the doc of Condition.await():
The current thread is assumed to hold the lock associated with this
Condition when this method is called. It is up to the implementation
to determine if this is the case and if not, how to respond.
Typically, an exception will be thrown (such as
IllegalMonitorStateException) and the implementation must document
that fact.
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
is similar with
ReentrantLock lock = new ReentrantLock();
Condition cond = lock.newCondition();
lock.lock();
try {
while (<condition does not hold>)
cond.await();
}
} finally {
lock.unlock();
}

IllegalMonitorStateException on a synchronized call to a Lock Condition's signalAll()

I have:
static public final ReentrantLock lock = new ReentrantLock();
static public Condition my_condition = lock.newCondition();
in myClass_1 and in myClass_2 class I call:
synchronized (myClass_1.my_condition){
myClass_1.my_condition.signalAll();
}
This is giving me the java.lang.IllegalMonitorStateException. I am already synchronizing over the signall() call. What could be causing it?
This is because you are not getting the lock of ReentrantLock before signalling.
Read below important statements from ReentrantLock#newCondition
If this lock is not held when any of the Condition waiting or
signalling methods are called, then an IllegalMonitorStateException is
thrown.
Also, read below from Condition. Now, like you cannot call wait() if thread is not acquiring the lock, same you wait or signal conditions if lock is not acquired.
Where a Lock replaces the use of synchronized methods and statements,
a Condition replaces the use of the Object monitor methods.
Bottom line: Acquire the lock before waiting or signalling the Condition.
lock.lock(); //Get the lock
while(/* whatever is your condition in myClass_1 and myClass_2 */){ //Or negative condition you want, but some code logic condition...
my_condition.await();
}
my_condition_2.signal(); //If you want to notify one thread. Like in case of Java's blocking queue, if you want to notify one thread to put or take.
my_condition_2.signalAll(); //If you want to notify all threads.
Do not use synchronized with Locks. Locks and Conditions replace synchronized/wait/notify; they should never be used in combination with it.
The documentation for ReeantrantLock.newCondition states:
If this lock is not held when any of the Condition waiting or signalling methods are called, then an IllegalMonitorStateException is thrown.
Correct use of a Lock and Condition looks like this:
lock.lock();
try {
someFlag = true;
condition.signalAll();
} finally {
lock.unlock();
}
And elsewhere:
lock.lock();
try {
someFlag = false;
while (!someFlag) {
condition.await();
}
} finally {
lock.unlock();
}
All Condition.await* methods must be called in a while-loop that checks the data the Condition represents, since the await* methods are subject to spurious wakeups (just like the Object.wait* methods).

How to understand if wait() returned from timeout or from a notify()?

I have a waiting thread:
synchronized(sharedCounter) {
while(sharedCounter > 0) {
sharedCounter.wait(60000); //wait at most 1 minute
/*if it wakens from the end of the timeout, it should break the loop
or it could potentially restart the timeout*/
}
}
And a thread that can notify:
synchronized (sharedCounter) {
if(sharedCounter == 0)
sharedCounter.notify();
}
How can I distinguish a notify from a timeout?
I could do something like this:
synchronized(sharedCounter) {
while(sharedCounter > 0) {
sharedCounter.wait(60000);
if(sharedCounter == -1) { //if it was a notify()
//I could save the fact that it was a notify() here
break;
}
//Otherwirse, assume it was a timeout, save the fact and break
break;
}
}
synchronized (sharedCounter) {
if(sharedCounter == 0) {
sharedCounter = -1; //to signal that it comes from a notify()
sharedCounter.notify();
}
}
The problem is, that a spurious wake up would spoil my design.
How would you handle this problem?
Use a more sophisticated concurrency primitive, a Condition. Acquire one from a Lock with Lock#newCondition(). You then have access to a Condition#await(long, TimeUnit) method which returns a boolean with a value of
false if the waiting time detectably elapsed before return from the method, else true
For example,
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// ... (share the object across threads)
if (condition.await(10, TimeUnit.SECONDS)) {
// signaled (equivalent of notify)
} else {
// time elapsed
}
// ... (in other thread)
condition.signal();
Spurious wakeups, unless otherwise specified in the Condition implementation documentation, are handled internally. You don't have to worry about them.
There is no way. You will have to add logic to your multithreaded application yourself to distinguish between these cases.
This is a false problem. If, for example, wait returned by timeout, but immediately after that sharedCounter was set to -1 - do you still want to react to timeout, or to -1?

ReentrantReadWriteLock - locking / releasing in if - else block

I have a question on ReadwriteLocks good practice. I've only ever used synchronized blocks before, so please bear with me.
Is the code below a correct way in which to use a ReadWriteLock? That is,
Obtain the lock in the private method.
If a condition is met, return from the private method having not released the lock. Release the lock in the public method.
Alternatively:
Obtain the lock in the private method.
If the condition is not met, release the lock immediately in the private method.
Many thanks
private List<Integer> list = new ArrayList<Integer>();
private ReadWriteLock listLock = new ReentrantReadWriteLock
public int methodA(int y) {
...........
long ago = methodB(y);
list.remove(y);
listLock.writeLock().unlock();
}
private long methodB(int x) {
listLock.writeLock().lock();
if(list.contains(x) {
long value = // do calculations on x
return value;
}
else {
listLock.writeLock().unlock();
// return something else unconnected with list
}
Normally when using locks you would do something similar to this.
Lock lock = ...; // Create type of lock
lock.lock();
try {
// Do synchronized stuff
}
finally {
lock.unlock();
}
This ensures that the lock is always unlocked at the end of the block. No matter if there is an exception thrown. Since you are using a reentrant lock you can place this in both methods and it will work correctly, not releasing the lock until the last finally block executes.
Edit: Javadocs for the Lock interface reinterates what I posted.

Thread Mutual Exclusive Section

Hello I just had phone interview I was not able to answer this question and would like to know the answer, I believe, its advisable to reach out for answers that you don't know. Please encourage me to understand the concept.
His question was:
"The synchronized block only allows one thread a time into the mutual exclusive section.
When a thread exits the synchronized block, the synchronized block does not specify
which of the waiting threads will be allowed next into the mutual exclusive section?
Using synchronized and methods available in Object, can you implement first-come,
first-serve mutual exclusive section? One that guarantees that threads are let into
the mutual exclusive section in the order of arrival? "
public class Test {
public static final Object obj = new Object();
public void doSomething() {
synchronized (obj) {
// mutual exclusive section
}
}
}
Here's a simple example:
public class FairLock {
private int _nextNumber;
private int _curNumber;
public synchronized void lock() throws InterruptedException {
int myNumber = _nextNumber++;
while(myNumber != _curNumber) {
wait();
}
}
public synchronized void unlock() {
_curNumber++;
notifyAll();
}
}
you would use it like:
public class Example {
private final FairLock _lock = new FairLock();
public void doSomething() {
_lock.lock();
try {
// do something mutually exclusive here ...
} finally {
_lock.unlock();
}
}
}
(note, this does not handle the situation where a caller to lock() receives an interrupted exception!)
what they were asking is a fair mutex
create a FIFO queue of lock objects that are pushed on it by threads waiting for the lock and then wait on it (all this except the waiting in a synchronized block on a separate lock)
then when the lock is released an object is popped of the queue and the thread waiting on it woken (also synchronized on the same lock for adding the objects)
You can use ReentrantLock with fairness parameter set to true. Then the next thread served will be the thread waiting for the longest time i.e. the one that arrived first.
Here is my attempt. The idea to give a ticket number for each thread. Threads are entered based on the order of their ticket numbers. I am not familiar with Java, so please read my comments:
public class Test {
public static final Object obj = new Object();
unsigned int count = 0; // unsigned global int
unsigned int next = 0; // unsigned global int
public void doSomething() {
unsigned int my_number; // my ticket number
// the critical section is small. Just pick your ticket number. Guarantee FIFO
synchronized (obj) { my_number = count ++; }
// busy waiting
while (next != my_number);
// mutual exclusion
next++; // only one thread will modify this global variable
}
}
The disadvantage of this answer is the busy waiting which will consume CPU time.
Using only Object's method and synchronized, in my point of view is a little difficult. Maybe, by setting each thread a priority, you can garantee an ordered access to the critical section.

Categories

Resources