Condition vs wait notify mechanism

JavaMultithreadingConcurrency

Java Problem Overview


What is the advantage of using Condition interface/implementations over the conventional wait notify mechanism? Here I quote the comments written by Doug Lea:

>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, by combining them with the use of arbitrary Lock implementations. Where a Lock replaces the use of synchronized methods and statements, a Condition replaces the use of the Object monitor methods.

I see this is a more Object Oriented way of implementing wait/notify mechanism. But is there a sound advantage over the former?

Java Solutions


Solution 1 - Java

The biggest problem is that wait/notify is error prone for new developers. The main problem is not knowing how to handle them correctly can result is obscure bug.

  • if you call notify() before wait() it is lost.
  • it can be sometimes unclear if notify() and wait() are called on the same object.
  • There is nothing in wait/notify which requires a state change, yet this is required in most cases.
  • wait() can return spuriously

Condition wraps up this functionality into a dedicated component, however it behaves much the same.

There is a question regarding wait/nofity posted minutes before this one and many, many more Search [java]+wait+notify

Solution 2 - Java

When you use Condition: await()/signal() you can distinguish which object or group of objects/threads get a specific signal. Here is a short example where some threads, the producers, will get the isEmpty signal while the consumers will get the isFull signal:

private volatile boolean usedData = true;//mutex for data
private final Lock lock = new ReentrantLock();
private final Condition isEmpty = lock.newCondition();
private final Condition isFull = lock.newCondition();

public void setData(int data) throws InterruptedException {
	lock.lock();
	try {
		while(!usedData) {//wait for data to be used
			isEmpty.await();
		}
		this.data = data;
		isFull.signal();//broadcast that the data is now full.
		usedData = false;//tell others I created new data.			
	}finally {
		lock.unlock();//interrupt or not, release lock
	}		
}

public void getData() throws InterruptedException{
	lock.lock();
	try {
		while(usedData) {//usedData is lingo for empty
			isFull.await();
		}
		isEmpty.signal();//tell the producers to produce some more.
		usedData = true;//tell others I have used the data.
	}finally {//interrupted or not, always release lock
		lock.unlock();
	}		
}

Solution 3 - Java

There are many advantages like mentioned above about Condition Interface some important are as follows:

Condition interface comes with Two extra methods that are:

1)boolean awaitUntil(Date deadline)throws InterruptedException : Causes the current thread to wait until it is signalled or interrupted, or the specified deadline elapses.

2)awaitUninterruptibly() : Causes the current thread to wait until it is signalled.

If the current thread's interrupted status is set when it enters this method, or it is interrupted while waiting, it will continue to wait until signalled. When it finally returns from this method its interrupted status will still be set.

The above two methods are not present in default monitor that is in object class,in some situations we want to set the deadline for thread to wait then we are able to do that by Condition interface.

In some situations we don't want thread to be interrupted and want current thread to wait until it is signaled then we can go for awaitUninterruptibly method present in Condition Interface.

For more information Condition Interface Java Documentation:

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Condition.html#awaitUntil%28java.util.Date%29

Solution 4 - Java

To specifically address why having multiple waitsets is an advantage:

With wait/notify if there are different things that threads are waiting for (the common example is a fixed size blocking queue, with some threads putting things in the queue and blocking when the queue is full, and other threads taking from the queue and blocking when the queue is empty) then if you use notify, causing the scheduler to pick one thread from the wait set to notify, you can have corner cases where the chosen thread isn't interested in being notified for a particular situation. For instance the queue will notify for adding something to the queue, but if the chosen thread is a producer and the queue is full then it can't act on that notification, which you would rather have gone to a consumer. With intrinsic locking you have to use notifyAll in order to make sure that notifications don't get lost.

But notifyAll incurs churn with every call, where every thread wakes up and contends for the lock, but only one can make progress. The other threads all bump around contending for the lock until, one at a time, they can acquire the lock and most likely go back to waiting. It generates a lot of contention for not much benefit, it would be preferable to be able to use notify and know only one thread is notified, where the notification is relevant to that thread.

This is where having separate Conditions to wait on is a big improvement. The queue can invoke signal on a condition and know it will wake up only one thread, where that thread is specifically waiting for the condition.

The API doc for Condition has a code example that shows using multiple conditions for a bounded buffer, it says:

> We would like to keep waiting put threads and take threads in separate wait-sets so that we can use the optimization of only notifying a single thread at a time when items or spaces become available in the buffer.

Solution 5 - Java

In addition to other well accepted answers - since Condition is associated with Lock object you can have arbitrary sets of Lock objects (reawrite, read, write) in your class and have specific condition associated with that. Then you can use those set of condition to synchronize different parts of your class according to your implementation semantics. This gives more flexibility and explicit behavior then wait-notify imo

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionuserxView Question on Stackoverflow
Solution 1 - JavaPeter LawreyView Answer on Stackoverflow
Solution 2 - JavakasavbereView Answer on Stackoverflow
Solution 3 - JavaKuldeep S. MahajanView Answer on Stackoverflow
Solution 4 - Javaпутин некультурная свиньяView Answer on Stackoverflow
Solution 5 - JavanirView Answer on Stackoverflow