• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Thread - Wait() and Notify();

 
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi All,

I am going through Thread chapter and will appretiate you explanations on following code (composed by me) and why I do not get expected results:



My output is:
ClassA: 0
ClassB: 1
ClassB: 2
ClassB: 3
ClassB: 4
ClassB: 5

What I expect is that ClassA will wakeup after each notify() in ClassB and result should be something like this:

ClassA: 0
ClassB: 1
ClassA: 1
ClassB: 2
ClassA: 2
ClassB: 3
ClassA: 3
ClassB: 4
ClassA: 4
ClassB: 5

What is wrong in my code? Do I have lock? or Main thread never get notify?

Thank you.
 
Greenhorn
Posts: 28
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Michael,

Even I had faced similar kinds of doubt when I was learning about threads. The output which you are expecting is not possible in this code. You are assuming that the notifyAll() method will actually release the lock on the object. But it is not so. The notifyAll() method informs the other waiting thread that the lock will be released soon and you can obtain the lock. Though the lock is actually released only after the entire syncronised block is executed. Till the time the thread is executing the code in synchronized block the lock is retained by the current thread and that what happens when the thread B sleeps the lock is still with it.

Hope this helps you in understanding why the output is not as expected by you.

Thanks
Hemnath
 
Ranch Hand
Posts: 320
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What you saw is what I would expect for the most part. It looks like A got in one time to fetch and print a value then hit the wait() which gives up the lock and blocks waiting on a notify()/notifyAll().

Then B gets into execution entering a synchronized block. Once it has the lock it executes a for loop incrementing it's variable, printing it out, calling notifyAll() and then sleeping.

What Hemnath said is critical here. The wait() in A releases the lock. The sleep() in B does NOT.

So the whole time you are in the loop in B the lock is held so A can not get into execution at all. B will most likely complete it's for loop then fall out to the bottom and it's thread will go into the dead state.
Now that B has exited the synchronized block, A can execute. It wakes up and continues in it's while loop. The condition of that while loop is while(t.isAlive()). Well.... it isn't any more. It exited and went to dead thread state so A just falls out of it's while loop without printing anything else.

This is a good piece of sample code to hang on to for teaching purposes. It shows the effect of sleeping with the locks held.
 
Michael Rootman
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

Ok I got the idea. Thank you for explanations.
Now, If I understand correctly, my expectations can be achieved by moving synchronized block inside the loop. So lock is release inside the loop and gives an opportunity to ClassA fetch the data.

it seems, that following changes do the work:




Do I missing safety this way?
 
Sheriff
Posts: 9708
43
Android Google Web Toolkit Hibernate IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Michael you are not understanding the concept. Notify cannot do anything as Main thread never waits on t object. Let's clear the basics first. t is an object. Both the run method and main method synchronize on it. When a thread holds a lock of an object, no other thread can synchronize on that object. There are two ways in which a lock can be released. 1) the synchronized code ends i.e. end of synchronized block or method, and 2) the thread which has the lock calls wait() on the object.

The change tat you made, might work or might not. The synchronized block starts and ends during each iteration of the loop. But there is only a notify call in there. But the notify call will do nothing as no other thread is 'waiting' on t object. So the call to notifyAll() is useless. Its true after each iteration, main method will get a chance to grab a lock on t, but even if that happens, then also this code will run only once and not after each iteration



So to create the behavior that you want, you need some wait calls which will give you guaranteed behavior of this output

ClassA: 0
ClassB: 1
ClassA: 1
ClassB: 2
ClassA: 2
ClassB: 3
ClassA: 3
ClassB: 4
ClassA: 4
ClassB: 5

Just try something more otherwise we will give you more hints...
 
Michael Rootman
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, Ankit,

Sorry, I am missing your point from this part....

Ankit Garg wrote:...Notify cannot do anything as Main thread never waits on t object..

It does. Line 34.

Ankit Garg wrote:... But the notify call will do nothing as no other thread is 'waiting' on t object...


If I look at the original code then line 34 has wait().
So from my prespective Main thread releases lock and waits for notification. Then another thread increases the number and in line 8 (changes from today) notifies other threads that work is done. Lock is released and lets to Main thread to work with t object. So why is

Ankit Garg wrote:... notify call will do nothing ..

? It lets Main thread to wake up and get the data. Doesn't it?

Ankit Garg wrote: Its true after each iteration, main method will get a chance to grab a lock on t, but even if that happens, then also this code will run only once and not after each iteration


Why not? I check if t thread is still alive (iteration is in progress) and while he is Main thread is trying to get the data and waiting for notification.

Please explain....



 
author
Posts: 23951
142
jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

it seems, that following changes do the work:

...

Do I missing safety this way?



From looking at your original code, it looks like the locks also protects the "results" variable. You need to get the "results++" statement within the sync lock, as it is now possible for the results to be incremented when the other thread is fetching it. (and since the increment operator is not atomic)

Henry
 
Henry Wong
author
Posts: 23951
142
jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

BTW, as a general note ... "blind" wait and notifes is generally not a good idea. Meaning.... there should be an explicit reason for the waits and notify.

1. A notify should satify an actual condition. It should grab the lock. Check that the condition needs to be satified. Satisfy that condition. Send the notify. And then release the lock.

2. A wait should only wait for a condition. It should grab the lock. Check the condition. Wait *only* if condition is not satisfied. (If wait, check the condition again. Wait again if not satified. (using a loop here)). Grab the data needed. Change the condition to taken. release the lock.

Basically, you should never trust that a condition is satified while a lock is released. You should always check after you acquire the lock, and after you return from wait -- as some other thread could have taken the condition while the lock is released.

Henry
 
Ankit Garg
Sheriff
Posts: 9708
43
Android Google Web Toolkit Hibernate IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I should probably go and bury myself somewhere. How could I not notice the while loop and the wait call . I must be insane when I was looking at the code...
 
Michael Rootman
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ankit Garg wrote:IHow could I not notice the while loop and the wait call



That is why you get 98% and not 100% :-)
 
Ankit Garg
Sheriff
Posts: 9708
43
Android Google Web Toolkit Hibernate IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well your program still doesn't gives the guaranteed behavior of the result you want. Actually you won't get the correct result most of the times. You need to do something more complicated to get reliable output

 
Michael Rootman
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

Ankit Garg wrote:Well your program still doesn't gives the guaranteed behavior of the result you want. Actually you won't get the correct result most of the times. You need to do something more complicated to get reliable output



Thank you for advices. Actually I got main result - I learned how wait() and notify() should be used.

 
reply
    Bookmark Topic Watch Topic
  • New Topic