why does my notify method not work properly? - java

I am improving my concurrent program by pausing threads that doing the same thing to wait for one of them finished. However, it cannot not wake up threads properly. Here is the code.
//to store graphs, if a thread finds the graph it is going to compute is in the entry, it waits, otherwise it compute then notify all other threads waiting on it.
Map<Graph, Object> entry = new ConcurrentHashMap<Graph, Object>();
public Result recursiveMethod(Graph g) {
if (entry.get(g) != null) {//if the graph is in the entry, waits
synchronized(entry.get(g)) {
entry.get(g).wait();
}
//wakes up, and directly return the result
return result;
}
synchronized(entry) {
if (entry.get(g) == null)//if the graph is not in the entry, continue to compute
entry.put(g,new Object());
}
//compute the graph recursively calls this method itself...
calculate here...
//wake up threads waiting on it, and remove the graph from entry
synchronized(entry.get(g)){
entry.get(g).notifyAll();
}
entry.remove(g);
return result;
}
This method is called by many many threads. Before a thread starts calculation, it looks up the entry to see if there is another thread calculating an identical graph. If so, it waits.
If not, it continues to calculate. After it figures out the result, it notifies all the threads that is waiting on it.
I use a map to pair up graph and an object. The object is the lock.
Please notice that the this map can recognize two identical graphs, that is, the following code returns true.
Graph g = new Graph();
entry.put(g, new Object());
Graph copy = new Graph(g);
entry.get(g) == entry.get(copy) //this is true
Thus, the entry.get(g) should be ok to be the lock/monitor.
However, most of the threads have not been awaken, only 3-4 threads has.
When the number of threads that is waiting equals to the number of threads that my computer can create, which means all the threads are waiting, this program would never terminate.
Why exactly does not the entry.get(g).notifyAll() work?

Due to the fact that you have un-synchronized gaps between times that you check the map and times that you operate on the map, you have many holes in your logic where threads can proceed incorrectly. you either need to synchronize outside of your map checks or use some of the special atomic methods for ConcurrentMaps.
when writing concurrent code, i like to pretend there is a malicious gnome running around in the background changing things wherever possible (e.g. outside of synchronized blocks). here's the first example to get you started:
if (entry.get(g) != null) {//if the graph is in the entry, waits
synchronized(entry.get(g)) {
you call entry.get() twice outside of a synchronization block. therefore, the value you get could be different between those 2 calls (the evil gnome changes the map as often as possible). in fact, it could be null when you try to synchronize on it, which will throw an exception.
additionally, wait() calls should always be made in a loop while waiting for a loop condition to change (due to the possibility of spurious wakeups, or, also in your case, multiple wakeups). lastly, you should change the loop condition before you notify. #AdrianShum gave a pretty good overview of how to use wait/notify correctly. your while loop should not be around everything, but within the synchronized block, around the wait call alone. this is not to deal with InterruptedException (a separate issue), but to deal with spurious wakeups and notifyAll calls. when you call notifyAll all waiting threads wake up, but only one can proceed, so the rest need to go back to waiting (hence the while loop).
in short, writing concurrent code is hard, and what you are attempting to implement is not simple. i would recommend reading a good book first (like Josh Bloch's "Java Concurrency In Practice") before attempting to finish this code.

In fact #jtahlborn has already raised the key of problem. I am trying to supplement by telling what's the most obvious issue here.
Try to get yourself understand the basics of Condition and why it can solve those race condition as normal signalling (in windows for example)
Your logic is something like this now (assume obj is referring to same object):
Thread 1:
if (!hasResult) {
synchronized(obj) {
obj.wait();
}
}
Thread 2:
hasResult = false;
// do your work
synchronized(obj) {
obj.notify();
}
hasResult= true;
You gotta know thread 1 and thread 2 is run in parallel, therefore you may have something like
Thread 1 Thread 2
hasResult = false
if (!hasResult)
do your work
synchronized(obj)
obj.notify()
end synchronized(obj)
synchronized(obj)
obj.wait()
end synchronized(obj)
Thread 1 is going to wait forever.
What you should do is
Thread 1:
synchronized(obj) {
while (hasResult) {
obj.wait();
}
}
Thread 2:
hasResult = false;
synchronized(obj) {
// do your work
obj.notify();
hasResult=true;
}
That's one of the biggest hole that #jtahlborn is talking I believe (and there are other). Note that setting condition and checking condition are all protected in synchronized block. That's the main basic idea of how Condition variable is solving the race condition illustrated before. Get yourself understand the idea first, and redesign your piece of code with something more reasonable.

Related

How does thread synchronization work in Kotlin?

I have been experimenting with Kotlin synchronization and I do not understand from the docs on how the locking mechanism works on thread synchronization over common resources and thus attempted to write this piece of code which further complicates my understanding.
fun main() {
val myList = mutableListOf(1)
thread {
myList.forEach {
while (true) {
println("T1 : $it")
}
}
}
thread {
synchronized(myList) {
while (true) {
myList[0] = 9999
println("**********\n**********\n**********\n")
}
}
}
}
myList is the common resource in question.
The first thread is a simple read operation that I intend to keep the resource utilized in read mode. The second is another thread which requests a lock in order to modify the common resource.
Though the first thread does not contain any synchronization, I would expect it to internally handle this so that a while a function like map or forEach is in progress over a resource, another thread should not be able to lock it otherwise the elements being iterated over may change while the map/forEach is in progress (even though that operation may be paused for a bit while another thread has a lock over it).
The output I see instead shows that both the threads are executing in parallel. Both of them are printing the first element in the list and the stars respectively. But in the second thread, even though the stars are being printed, myList[0] is never set to 9999 because the first thread continues to print 1.
Threading and synchronisation are JVM features, not specific to Kotlin. If you can follow Java, there are many resources out there which can explain them fully. But the short answer is: they're quite low-level, and tricky to get right, so please exercise due caution. And if a higher-level construction (work queues/executors, map/reduce, actors...) or immutable objects can do what you need, life will be easier if you use that instead!
But here're the basics. First, in the JVM, every object has a lock, which can be used to control access to something. (That something is usually the object the lock belongs to, but need not be...) The lock can be taken by the code in a particular thread; while it's holding that lock, any other thread which tries to take the lock will block until the first thread releases it.
And that's pretty much all there is! The synchronised keyword (actually a function) is used to claim a lock; either that belonging to a given object or (if none's given) 'this' object.
Note that holding a lock prevents other threads holding the lock; it doesn't prevent anything else. So I'm afraid your expectation is wrong. That's why you're seeing the threads happily running simultaneously.
Ideally, every class would be written with some consideration for how it interacts with multithreading; it could document itself as 'immutable' (no mutable state to worry about), 'thread-safe' (safe to call from multiple threads simultaneously), 'conditionally thread-safe' (safe to call from multiple threads if certain patterns are adhered to), 'thread-compatible' (taking no special precautions but callers can do their own synchronisation to make it safe), or 'thread-hostile' (impossible to use from multiple threads). But in practice, most don't.
In fact, most turn out to be thread-compatible; and that applies to much of the Java and Kotlin collection classes. So you can do your own synchronisation (as per your synchronized block); but you have to take care to synchronise every possible access to the list -- otherwise, a race condition could leave your list in an inconsistent state.
(And that can mean more than just a dodgy value somewhere. I had a server app with a thread that got stuck in a busy-loop -- chewing up 100% of a CPU but never continuing with the rest of the code -- because I had one thread update a HashMap while another thread was reading it, and I'd missed the synchronisation on one of those. Most embarrassing.)
So, as I said, if you can use a higher-level construction instead, your life will be easier!
Second thread is not changing the value of the first list element, as == means compare, not assign. You need to use = tio change the value e.g. myList[0] = 9999. However in your code it's not guaranteed that the change from the second thread will become visible in the first thread as thread one is not synchronising on myList.
If you are targeting JVM you should read about JVM memory model e.g. what is #Volatile. You current approach does not guarantee that first thread will ever see changes from the second one. You can simplify your code to below broken example:
var counter = 1
fun main() {
thread {
while (counter++ < 1000) {
println("T1: $counter")
}
}
thread {
while (counter++ < 1000) {
println("T2: $counter")
}
}
}
Which can print strange results like:
T2: 999
T1: 983
T2: 1000
This can be fixed in few ways e.g. by using synchronisations.

Access to shared resource, lock unlock or wait notify

Scenario:
Multi-threads reading from different sources.
One single access point to a shared queue (See a class RiderSynchronized trying to write)
Every line a Reader reads, It tries to insert into a shared queue through method RiderSynchronized provides.
When shared queue is full, I have to run a batch on a prepared statement to insert into Oracle. Meanwhile, all access to shared queue it must be denied.
Code:
public class RiderSynchronized {
private ArrayDeque<JSONRecord> queue = new ArrayDeque<>();
private OracleDAO oracleDao;
private long capacity;
public RiderSynchronized(OracleDAO oracleDao, long capacity) {
this.oracleDao = oracleDao;
this.capacity = capacity;
}
public synchronized boolean addRecord(JSONRecord record) {
boolean success = false;
try {
while (queue.size() >= capacity) {
wait();
}
queue.add(record);
if (queue.size() < capacity) {
success = true;
notify(); //notify single Thread
} else {
JSONRecord currentRecord = null;
while ((currentRecord = queue.poll()) != null) {
oracleDao.insertRowParsedIntoBatch(currentRecord);
}
oracleDao.runBatch();
success = true;
notifyAll(); //it could be all Reading Threads are waiting. Notify all
}
} catch (Exception e) {
success = false;
}
return success;
}
}
I have to admit I'm a little worried about a thing.
1) Reader threads can just use addRecord indistinctly? Are They going to wait for themselves? Or Do I have to implement some other method where to check before to run addRecord Method?
2) When queue.size < capacity, I decide to notify just to one thread, because IMHO, at this point, no threads should be in status waiting. Am I wrong? Should I notify All?
2b) Exact question for the "else" statement. Is it a good practice to notifyAll? At this point, it could be all threds are waiting?
3) Finally. I'm a little concerned to re-write everything using Lock e Condition Classes. Is it a better decision? Or Is it ok how I'm running this scenario?
1) Reader threads can just use addRecord indistinctly? Are They going
to wait for themselves? Or Do I have to implement some other method
where to check before to run addRecord Method?
The problem with your current code is that if for some reason notifyAll is not called by the only thread that theoretically should be able to go into the else block then your threads will wait forever.
The potential risks in your code are:
oracleDao.insertRowParsedIntoBatch(currentRecord)
oracleDao.runBatch()
With your current code if one of those methods throw an exception notifyAll will never be called so your threads will wait forever, you should at least consider calling notifyAll in a finally block to make sure that it will be called whether happens.
2) When queue.size < capacity, I decide to notify just to one thread,
because IMHO, at this point, no threads should be in status waiting.
Am I wrong? Should I notify All?
Your threads could only wait in case queue.size() >= capacity so for me notify is not even needed as this condition (queue.size() < capacity) is not expected by any thread.
2b) Exact question for the "else" statement. Is it a good practice to
notifyAll? At this point, it could be all threds are waiting?
Item 69 from Effective Java:
A related issue is whether you should use notify or notifyAll to wake
waiting threads. (Recall that notify wakes a single waiting thread,
assuming such a thread exists, and notifyAll wakes all waiting
threads.) It is often said that you should always use notifyAll. This
is reasonable, conservative advice. It will always yield correct
results because it guarantees that you’ll wake the threads that need
to be awakened. You may wake some other threads, too, but this won’t
affect the correctness of your program. These threads will check the
condition for which they’re waiting and, finding it false, will
continue waiting. As an optimization, you may choose to invoke notify
instead of notifyAll if all threads that could be in the wait-set are
waiting for the same condition and only one thread at a time can
benefit from the condition becoming true. Even if these conditions
appear true, there may be cause to use notifyAll in place of notify.
Just as placing the wait invocation in a loop protects against
accidental or malicious notifications on a publicly accessible object,
using notifyAll in place of notify protects against accidental or
malicious waits by an unrelated thread. Such waits could otherwise
“swallow” a critical notification, leaving its intended recipient
waiting indefinitely.
3) Finally. I'm a little concerned to re-write everything using Lock e
Condition Classes. Is it a better decision? Or Is it ok how I'm
running this scenario?
Lock and Condition are interesting if you need features that are not available with intrinsic locks like for example tryLock() or the ability to awake only threads waiting for a given condition. In your case it doesn't seem to be necessary so you can keep it like it is.
I'll try to answer you question one by one.
1) If I understand you correctly answer is yes thread will wait and you don't need to do anything else.
2) You don't need to notify anyone in case of queue.size < capacity there are no waiting thread at this point.
3) Yes it is ok to notify all. If more threads than capacity is waiting rest of them come to wait state fast.
4) It is opinion based question. In your scenario you wont get any benefit from rewriting.

Wait vs No wait in Synchronized methods (java)

Hi I'm pretty new to Java and now I'm getting into java concurrency. And I have a little doubt about Synchronized methods: i have seen that I can get the same results using an If else inside a Synchronized method, checking every time If the condition to do an action is fullfilled, as using a wait / notify approach.
Since i get the same result I'm wondering If the If else approach has any advantages or disadvantages over t'he wait and notify approach? I supose that efficiency will be a disadvantage, since If is always checking the condition, Who le wait Just stops and waits for notify. But are any other advantages or disadvantages?
Thx!
You are mixing two concepts. If-Else vs Wait-Notify are totally different. You want two threads to communicate with each-other that is where Wait-Notify would be used while if-else is general conditional statement.
You cannot have two threads communicate with each other simply using if-else condition. You can write your code that makes it look like it does however you are simply not allowing threads to interact with each other.
Moreover it can lead to undesirable consequences/computational states. Sooner or later you would have hotchpotch code.
synchronized block makes the code thread safe. You would want to use wait() and notify() or notifyAll() if you want to be more efficient.
For example if your shared resource is a list, multiple threads share. If you put it in synchronized block of a monitor then threads will constantly jump in and run the code, during context switches. Even if the list is enpty!!
The wait() is hence used on the monitor (the object inside the synchronized(..)) as a mechanism to 'tell' all threads to chill out and stop using CPU cycles until further notice or notifyAll().
synchronized(monitor) {
while( list.isEmpty() )
monitor.wait();
doSomething(...)
}
In the above example, doSomething() will be executed only when the list is not empty, after another thread executed notify() or notifyAll() somewhere else in the code.
read more why use while surrounding wait()
BUT with the following code:
synchronized(monitor) {
if(!list.isEmpty())
doSomething(...)
}
When a thread comes in to the synchronized block, there are 3 possible scenarios:
The list is empty: doSomething() will not be executed.
The list is NOT empty: doSomething() may be executed properly, or...
If there was a context switch right after the if and before doSomething, and the other thread got all list's items out, after another context-switch out thread will execute doSomethig() on an empty list.
So, just to sum everything up, if you use wait/notify, you guarantee more efficient code! thread will not work when they don't need to.

Using 'this' versus another object as lock in synchronized block with wait and notify

I have two blocks of code, one waits for the other to notify it.
synchronized(this) {
wait();
}
and
while(condition) {
//do stuff
synchronized(this) {
notify();
}
}
Weirdly enough that didn't wait for the notify while this did:
synchronized(objectLock) {
objectLock.wait();
}
and
while(condition) {
//do stuff
synchronized(objectLock) {
objectLock.notify();
}
}
I'm very curious about the difference of both sets, and why the first one worked while the other didn't. Note that the two blocks reside in two different threads on two different methods (if that helps).
I hope someone could explain why this is so. I edited my question so it would be more detailed.
It didn't work because you synchronized on this which in two different threads pointed to two different Thread objects.
Synchronization with wait() and notify() would only work properly when you synchronize on the same object for locking like the objectLock that you used later on.
EDIT:
If the two thread instances belonged to the same MyThread class then to achieve the effect that you thought you're code was having, you would have to acquire a lock on their class object itself:
synchronized(MyThread.class)
You can use any object you like. However, it is generally clearer to other programmers to see an explicit lock object.
My wild guess as to why this didn't work for you is you had a different this in scope. (ie, in an anonymous function/callback). You can be explicit about which this to use by appending the class name, eg, WonderClass.this - again a reason why this is not as clear. (edit: actually WhateverClass.this won't help you if this really is a different instance)
Also do read this: http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html - I generally find it easier to put all the thread-unsafe code into small synchronized methods (which do an implict lock on this)
When you say the two blocks reside in two different threads that makes me think they're not locking on the same object because this is not the same thing. When you name an explicit lock you're using the same thing to lock on.
By the way you should call wait in a loop, like this:
synchronized(someLock) {
while (!someCondition) {
wait();
}
// now the thread has the lock and it can do things
// knowing for sure that someCondition is true
}
Without this you will be vulnerable to spurious wakeups (not all notifications come from your application code) and the order in which wait and notify are called becomes problematic (if you have two threads and one notifies before the other waits then that notification never gets seen).
I'd advise using the Monitor pattern (http://en.wikipedia.org/wiki/Monitor_(synchronization)) anyway, that could save you from errors later on, especially as your use case gets more complex:
class Monitor
{
/** Initialised to `false` by default in Java. */
boolean condition;
synchronized void waitForSomething()
{
while(!condition)
{
wait();
}
}
synchronized void signal()
{
condition = true;
notify();
}
}
That way everything is nicely encapsulated and protected (I don't usually use private modifiers in examples, but you might want to enforce additional "privacy" in your code, specifically making the condition private.)
As you can observe, in my condition loop there is wait() call, as opposed to your example where you have notify() in the loop instead. In most use cases doing what you did with notify is a mistake, although I can't speak for your particular case as you didn't provide us with enough details. I am willing to bet yours is the typical one though, for which the Monitor pattern applies beautifully.
The usage scenario is along the following: thread that wants to wait for something calls waitForSomething and another thread may cause it to continue by invoking signal method which will set the condition flag.

Why should wait() always be called inside a loop

I have read that we should always call a wait() from within a loop:
while (!condition) { obj.wait(); }
It works fine without a loop so why is that?
You need not only to loop it but check your condition in the loop. Java does not guarantee that your thread will be woken up only by a notify()/notifyAll() call or the right notify()/notifyAll() call at all. Because of this property the loop-less version might work on your development environment and fail on the production environment unexpectedly.
For example, you are waiting for something:
synchronized (theObjectYouAreWaitingOn) {
while (!carryOn) {
theObjectYouAreWaitingOn.wait();
}
}
An evil thread comes along and:
theObjectYouAreWaitingOn.notifyAll();
If the evil thread does not/can not mess with the carryOn you just continue to wait for the proper client.
Edit: Added some more samples.
The wait can be interrupted. It throws InterruptedException and you might need to wrap the wait in a try-catch. Depending on your business needs, you can exit or suppress the exception and continue waiting.
It's answered in documentation for Object.wait(long milis)
A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops, like this one:
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}
(For more information on this topic,
see Section 3.2.3 in Doug Lea's
"Concurrent Programming in Java
(Second Edition)" (Addison-Wesley,
2000), or Item 50 in Joshua Bloch's
"Effective Java Programming Language
Guide" (Addison-Wesley, 2001).
Why should wait() always be called inside a loop
The primary reason why while loops are so important is race conditions between threads. Certainly spurious wakeups are real and for certain architectures they are common, but race conditions are a much more likely reason for the while loop.
For example:
synchronized (queue) {
// this needs to be while
while (queue.isEmpty()) {
queue.wait();
}
queue.remove();
}
With the above code, there may be 2 consumer threads. When the producer locks the queue to add to it, consumer #1 may be blocked at the synchronized lock while consumer #2 is waiting on the queue. When the item is added to the queue and notify called by the producer, #2 is moved from the wait queue to be blocked on the queue lock, but it will be behind the #1 consumer which was already blocked on the lock. This means that the #1 consumer gets to go forward first to call remove() from the queue. If the while loop is just an if, then when consumer #2 gets the lock after #1 and calls remove(), an exception would occur because the queue is now empty -- the other consumer thread already removed the item. Even though it was notified, it needs to be make sure the queue is for sure not empty because of this race condition.
This well documented. Here's a web page I created a while back which explains the race condition in detail and has some sample code.
There might be more then just one worker waiting for a condition to become true.
If two or more worker get awake (notifyAll) they have to check the condition again.
otherwise all workers would continue even though there might only be data for one of them.
I think I got #Gray 's answer.
Let me try to rephrase that for newbies like me and request the experts to correct me if I am wrong.
Consumer synchronized block::
synchronized (queue) {
// this needs to be while
while (queue.isEmpty()) {
queue.wait();
}
queue.remove();
}
Producer synchronized block::
synchronized(queue) {
// producer produces inside the queue
queue.notify();
}
Assume the following happens in the given order:
1) consumer#2 gets inside the consumer synchronized block and is waiting since queue is empty.
2) Now, producer obtains the lock on queueand inserts inside the queue and calls notify().
Now,either consumer#1 can be chosen to run which is waiting for queue lock to enter the synchronized block for the first time
or
consumer#2 can be chosen to run.
3) say, consumer#1 is chosen to continue with the execution. When it checks the condition,it will be true and it will remove() from the queue.
4) say,consumer#2 is proceeding from where it halted its execution (the line after the wait() method). If 'while' condition is not there (instead an if condition), it will just proceed to call remove() which might result in an exception/unexpected behaviour.
Because wait and notify are used to implement [condition variables](http://en.wikipedia.org/wiki/Monitor_(synchronization)#Blocking_condition_variables) and so you need to check whether the specific predicate you're waiting on is true before continuing.
Both safety and liveness are concerns when using the wait/notify mechanism. The safety property requires that all objects maintain consistent states in a multithreaded environment. The liveness property requires that every operation or method invocation execute to completion without interruption.
To guarantee liveness, programs must test the while loop condition before invoking the wait() method. This early test checks whether another thread has already satisfied the condition predicate and sent a notification. Invoking the wait() method after the notification has been sent results in indefinite blocking.
To guarantee safety, programs must test the while loop condition after returning from the wait() method. Although wait() is intended to block indefinitely until a notification is received, it still must be encased within a loop to prevent the following vulnerabilities:
Thread in the middle: A third thread can acquire the lock on the shared object during the interval between a notification being sent and the receiving thread resuming execution. This third thread can change the state of the object, leaving it inconsistent. This is a time-of-check, time-of-use (TOCTOU) race condition.
Malicious notification: A random or malicious notification can be received when the condition predicate is false. Such a notification would cancel the wait() method.
Misdelivered notification: The order in which threads execute after receipt of a notifyAll() signal is unspecified. Consequently, an unrelated thread could start executing and discover that its condition predicate is satisfied. Consequently, it could resume execution despite being required to remain dormant.
Spurious wakeups: Certain Java Virtual Machine (JVM) implementations are vulnerable to spurious wakeups that result in waiting threads waking up even without a notification.
For these reasons, programs must check the condition predicate after the wait() method returns. A while loop is the best choice for checking the condition predicate both before and after invoking wait().
Similarly, the await() method of the Condition interface also must be invoked inside a loop. According to the Java API, Interface Condition
When waiting upon a Condition, a "spurious wakeup" is permitted to
occur, in general, as a concession to the underlying platform
semantics. This has little practical impact on most application
programs as a Condition should always be waited upon in a loop,
testing the state predicate that is being waited for. An
implementation is free to remove the possibility of spurious wakeups
but it is recommended that applications programmers always assume that
they can occur and so always wait in a loop.
New code should use the java.util.concurrent.locks concurrency utilities in place of the wait/notify mechanism. However, legacy code that complies with the other requirements of this rule is permitted to depend on the wait/notify mechanism.
Noncompliant Code Example
This noncompliant code example invokes the wait() method inside a traditional if block and fails to check the postcondition after the notification is received. If the notification were accidental or malicious, the thread could wake up prematurely.
synchronized (object) {
if (<condition does not hold>) {
object.wait();
}
// Proceed when condition holds
}
Compliant Solution
This compliant solution calls the wait() method from within a while loop to check the condition both before and after the call to wait():
synchronized (object) {
while (<condition does not hold>) {
object.wait();
}
// Proceed when condition holds
}
Invocations of the java.util.concurrent.locks.Condition.await() method also must be enclosed in a similar loop.
Before getting to the answer, lets see how wait is probably implemented.
wait(mutex) {
// automatically release mutex
// and go on wait queue
// ... wait ... wait ... wait ...
// remove from queue
// re-acquire mutex
// exit the wait operation
}
In your example mutex is the obj with the assumption that your code is running inside synchronized(obj) { } block.
A mutex is called as monitor in Java [some subtle differences though]
A concurrency example using condition variable with if
synchronized(obj) {
if (!condition) {
obj.wait();
}
// Do some stuff related to condition
condition = false;
}
Lets say we have 2 threads. Thread 1 and Thread 2.
Lets see some states along the timeline.
at t = x
Thread 1 state:
waiting on ... wait ... wait ... wait ..
Thread 2 state:
Just entered the synchronised section, since as per the thread 1's state, the mutex/monitor is released.
You can read more about wait() here java.sun.com/javase/6/docs/api/java/lang/Object.html#wait(long).
This is the only thing that is tricky to understand. When 1 thread is inside the synchronized block. Another thread can still enter the synchronized block because wait() causes the monitor/mutex to be released.
Thread 2 is about to read if (!condition) statement.
at t = x + 1
notify() is triggered by some thread on this mutex/monitor.
condition becomes true
Thread 1 state:
Waiting at re-acquire mutex, [Since thread-2 has the lock now]
Thread 2 state:
Doesn't go inside if condition and marks the condition = false.
at t = x + 2
Thread 1 state:
Exits the wait operation and about to mark condition = false.
This state is inconsistent as condition is supposed to be true but is false already, because thread 2 marked it false previously.
And thats the reason, while is required instead of if. As while would trigger the condition to be checked again for thread 1 and thread 1 will begin waiting again.
Result
In order to avoid this inconsistency the correct code seems to be like this:
synchronized(obj) {
while (!condition) {
obj.wait();
}
// Do some stuff related to condition
condition = false;
}
From your Question:
I have read that we should always called a wait() from within a loop:
Although wait( ) normally waits until notify( ) or notifyAll( ) is called, there is a possibility that in very rare cases the waiting thread could be awakened due to a spurious wakeup. In this case, a waiting thread resumes without notify( ) or notifyAll( ) having been called.
In essence, the thread resumes for no apparent reason.
Because of this remote possibility, Oracle recommends that calls to wait( ) should take place within a loop that checks the condition on which the thread is waiting.
Three things you will see people do:
Using wait without checking anything (BROKEN)
Using wait with a condition, using an if check first (BROKEN).
Using wait in a loop, where the loop test checks the condition (NOT BROKEN).
Not appreciating these details about how wait and notify work leads people to choose the wrong approach:
One is that a thread doesn't remember notifications that happened before it got around to waiting. The notify and notifyAll methods only effect threads that are already waiting, if a thread isn't waiting at the time it is out of luck.
Another is that a thread releases the lock once it starts waiting. Once it gets a notification it re-acquires the lock and continues on where it left off. Releasing the lock means that thread does not know anything about the current state once it wakes back up, any number of other threads could have made changes since then. The check made before the thread started waiting doesn't tell you anything about what the state is currently.
So the first case, with no checking, makes your code vulnerable to race conditions. It might happen to work by accident if one thread has enough of a head start over another. Or you may have threads waiting forever. If you sprinkle in timeouts then you end up with slow code that sometimes doesn't do what you want.
Adding a condition to check apart from the notification itself protects your code from these race conditions and gives your code a way to know what the state is even if the thread wasn't waiting at the right time.
The second case, with if-checks, is likely to work if you have only 2 threads. That puts a limit on the number of states things can get into and when you made faulty assumptions you don't get burned so badly. This is the situation for lots of toy example code exercises. The result is people come away thinking they understand, when they really don't.
Protip: Real world code has more than two threads.
Using the loop lets you re-check the condition once you re-acquire the lock so that you're moving forward based on current state, not on stale state.
In simple words,
'if' is a conditional statement , once condition is satisfied remaining block of code will get executed.
'while' is a loop which going check the condition unless condition is not satisfied.

Categories

Resources