aspose file tools*
The moose likes Threads and Synchronization and the fly likes Threading discrepancies Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Threads and Synchronization
Bookmark "Threading discrepancies" Watch "Threading discrepancies" New topic
Author

Threading discrepancies

fahad siddiqui
Ranch Hand

Joined: Jun 14, 2006
Posts: 85
I am pasting 2 versions of the same code of threading.



This is the working version.
Below is the non-working version of the code.


What happens is, when i notify from the calculator, only 1 of the waiting thread will run. But in the previous version of the code, all the 3 waiting threads run.

What is the reason for such a response? Please explain.
[ September 12, 2007: Message edited by: Jim Yingst ]
Edward Harned
Ranch Hand

Joined: Sep 19, 2005
Posts: 291

Code tags are with [] not <>. Use the buttons to insert the code tags.

Without formatting, the code is such a mess, I give up.

In order to notify multiple threads, you need to use notifyAll() not notify().


Ed's latest article: A Java Parallel Calamity http://coopsoft.com/ar/Calamity2Article.html
fahad siddiqui
Ranch Hand

Joined: Jun 14, 2006
Posts: 85
Is the code not visible properly? I am able to view it properly.

Also, i am using notify(), which means only 1 waiting thread should execute and finish.
But yet, all the 3 threads get notified somehow in the older version of the code and i get 3 output statements instead of just 1.
The new version in which i used implements Runnable, that works fine and only 1 thread gets notified.

I want to know the reason for the failure of the older version of code.
fahad siddiqui
Ranch Hand

Joined: Jun 14, 2006
Posts: 85
here is the code again:

The current properly working version i.e. when the calculator thread notify(), only 1 of the reader thread executes and 1 output is printed.




Below pasted in the older version of the code, in which upon notify() from the calculator thread, all the 3 reader threads get notified and i get 3 output statements.



I hope the problem is understood.
Edward Harned
Ranch Hand

Joined: Sep 19, 2005
Posts: 291

The moderator fixed your code tags.

What is the difference between the two snippets? You don't really think I'm going to parse your code looking for the differences myself, do you?

Explain exactly what it is your are doing and what results you want and what you did to resolve this yourself.
fahad siddiqui
Ranch Hand

Joined: Jun 14, 2006
Posts: 85
The current version has calculator implements Runnable and the lock object is the current instance of calculator.

In the older version, calculator extends Thread and the lock object is the current instance of calculator.

In the current version, calculator notifies and 1 instance of reader executes after wait and prints the statement while in the older version, upon notify(), all the 3 reader threads get notified and print the statement.
fahad siddiqui
Ranch Hand

Joined: Jun 14, 2006
Posts: 85
The current version has calculator implements Runnable and the lock object is the current instance of calculator.

In the older version, calculator extends Thread and the lock object is the current instance of calculator.

In the current version, calculator notifies and 1 instance of reader executes after wait and prints the statement while in the older version, upon notify, all the 3 reader threads get notified and print the statement.
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
fahad, both versions of the code above seem to do the same thing. Only one thread responds. That's because notify() only notifies one thread. I suggest you try using notifyAll() instead.


"I'm not back." - Bill Harding, Twister
Edward Harned
Ranch Hand

Joined: Sep 19, 2005
Posts: 291

OK. I ran both versions and its like you say.

This is going to take a while to figure out. I'm sure its simple and obvious, but I just don't see it yet.
Edward Harned
Ranch Hand

Joined: Sep 19, 2005
Posts: 291

A little more research lead me to the API for Object.wait(), see here:

"interrupts and spurious wakeups are possible, and this method should always be used in a loop:


Looks like that may be the reason.
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
For Calculator_Old and Reader_Old, the behavior varies. I've seen it print "Total is" once, twice, or three times. Three times seems most common, but the first time I ran it it printed once, and I've seen all three results more than once.

So, how can there be more than one notification, if Calculator_Old is using notify() rather than notifyAll()? The answer is that a Thread actually does a notifyAll() when it ends. This is used by join() to wake it up to see that the thread has died. This isn't really documented, but the JLS does mention the possibility of "spurious wakeups".

So why does the result vary? Well, sometimes Reader_Old gets to the wait() after the calculator has finished - meaning the notifyAll() has already been sent. In that case, it will wait forever.
fahad siddiqui
Ranch Hand

Joined: Jun 14, 2006
Posts: 85
So, then in such a kind of scenario, i cant take it for granted that only one of the reader threads will be notified.

But why does it work properly in the current version, when i have made calculator implements Runnable. Such a variable behaviour should be found in this case also, but it never happens. I tried it on couple of machines. It always notifies a single time.
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
[fahad]: But why does it work properly in the current version, when i have made calculator implements Runnable.

From my last post: The answer is that a Thread actually does a notifyAll() when it ends. If your Calculator class extends Thread, then your Calculator will do a notifyAll() after it's completed its run() method. If your Calculator does not extends Thread, but merely implements Runnable, then it won't do a notifyAll(). In that case there's only one notify(), the one you put in the code. It's still theoretically possible for spurious wakeups to occur for some other reason, but this is generally unlikely and it's also entirely possible that you will never observe them.

If you need to guarantee that only one thread gets woken up, well, you can't. But you could add some additional logic that ensures that if more than one thread is woken up, the additional threads resume wiat() state until another notify() occurs for some other reason. In practice I doubt you'd need such a guarantee, but I really have little idea what you're trying to do here, so who knows? If you're just trying to be efficient, notifying only one thread because one thread is all that can act successfully, then spurious wakeups are unlikely anyway, but if they occur, they're not really harmful, just less efficient than you would like. But the effort to prevent them entirely is almost certainly more work for the JVM than it is to simply let them occur.
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24184
    
  34

And the real lesson here is to never call wait() on a Thread object, because (as Jim says,) Thread uses wait() and notify() for its own purposes, and any use you try to make of it will just interfere with that.


[Jess in Action][AskingGoodQuestions]
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
Hm, well, I'd cast the lesson a little differently.

Most importantly, as Josh Bloch says: Never invoke wait() outside a loop. The loop condition should check to see whether or not the thing you're really waiting for is true or not, and only exit the loop if the condition has been fulfilled. This takes care of those mysterious "spurious wakeups" as well as less-mysterious things like the undocumented notifyAll() called on Thread instances just before they die. It also takes care of a numbe rof other common programming errors. Never assume that just because your thread has woken up, it's tiime to move forward. Check to make sure it's so. This check can always be expressed as a boolean end condition in a loop - that's what Bloch's admonishment is about.

Second, and less commonly known and agreed on: avoid synchronizing on any instance which is available to other classes. You never know what strange use other programmers might have for that instance - sync on it? Wait on it? Call notify on it? Sync on it and then sync on something else which creates deadlock? In this case, the "this" instance (of class Calculator_Old) is also used by class Thread for its own mysterious purposes, requiring that class to sync on the "this" instance to perform a notifyAll(). If any other classes were already synchronized on that same instance, this could produce deadlock. In the current situation it doesn't, but it does produce an apparently spurious wakeup, as notifyall() is called on "this". Better if there were a private member:

private final Object lock = new Object();

and if synchonization, waiting and notification were performed using this "lock" object, rather than "this". (You can also replace the "lock" with a java.util.concurrent.locks.Lock if you wish, but that's more advanced.) Then there would be (almost) no chance that another thread had already acquired a sync lock on the same instance. And similarly the chance of a "spurious" (or undocumented) wakeup would be greatly reduced, although to be fair you should still code as though this is a possibility.

In fairness though, in my experience the second consideration is usually merely theoretical, while the first is almost always practical. Never invoke wait() outside of a loop, and make sure that the loop condition will not exit unless the thing you're really waiting for has occurred.
Edward Harned
Ranch Hand

Joined: Sep 19, 2005
Posts: 291

Thank you Jim Yingst for the pointer about notifyAll(). I found that code in the remove(ThreadGroup g) method of ThreadGroup.

An interesting point about calling wait/notify on Thread objects. Sun should document this or at least warn people.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Threading discrepancies