What is happening when a thread releases a lock on an object ?

R

Razvan

Hi !




When the object is released from a lock (at the end of the
synchronized block) a notify message gets sent by default ? The
following piece of code seems to suggest that:



public class CThread extends Thread
{
public static void main(String args[])
{
// create & start the FIRST thread
CThread th1 = new CThread();
System.out.println("\nStarting thread 1...\n");
th1.start();


// sleep for a second
try { Thread.sleep(1000); }
catch(InterruptedException ee) { System.out.println("The main thread
was interrupted !"); }


// create & start the SECOND thread
Runner rn = new Runner(th1);
Thread th2 = new Thread(rn);
System.out.println("\nStarting thread 2...\n");
th2.start();
}


public synchronized void run()
{
int ii = 3;

while(ii > 0)
{
System.out.println("\t\t\tthread 1: \t\t\tii=" + ii);

notify();

try { wait(); }
catch(InterruptedException ee) { System.out.println("Thread 1
interrupted from wait [1]!"); }

ii--;
}

System.out.println("\nThread 1 is waiting for 5 seconds !");
try {
// notify(); // if I notify here the second thread will finish
first
// if I don't notify the first one will finish first
// this seems to point to the fact that at the end of
// the synchronized method run() some notify() message is sent
wait(5000);
}
catch(InterruptedException ee) { System.out.println("Thread 1
interrupted from wait [2]!"); }

System.out.println("Thread 1 has finished !");
}
}



class Runner implements Runnable
{
CThread externalThreadObject;

// Runner constructor
Runner(CThread externalThreadObject) { this.externalThreadObject =
externalThreadObject; }


public void run()
{
int ii = 3;

while(ii > 0)
{
System.out.println("\t\t\tthread 2: \t\t\tii=" + ii);

synchronized(externalThreadObject)
{
externalThreadObject.notify();

try {
externalThreadObject.wait();
}
catch(InterruptedException ee) {
System.out.println("Second thread interrupted from wait !");
}
}
ii--;
}
System.out.println("Thread 2 has finished !");
}
}









Normally the second thread should hang indefinitively in the wait()
call (the wait call has no timeout) but it is not. As soon as the
first thread finishes the synchronized block, the second thread
receives a notify() message from somewhere and the wait() call ends.

Why is this happening ?





Regards,
Razvan
 
B

Babu Kalakrishnan

Razvan said:
Normally the second thread should hang indefinitively in the wait()
call (the wait call has no timeout) but it is not. As soon as the
first thread finishes the synchronized block, the second thread
receives a notify() message from somewhere and the wait() call ends.

Why is this happening ?

You're synchronizing on a Thread object, and it is very probable that it must be
calling a notifyAll() before it terminates.

That brings up one very important point one should always remember while using
the wait/ notify mechanism. You should always be prepared for unexpected
notify() calls to arrive when you are "wait()ing". Receiving a notify is not
sufficient indication that a condition that you're looking for has been
satisfied. There is never a guarantee that the super class of the object you
are using as the monitor will not call notify() or notifyAll() on itself during
the execution of some of its instance methods.

That is the reason why the construct

synchronized (object)
{
while (somecondition)
{
object.wait();
}
}

is the most commonly employed one (InterruptedException handling skipped for
clarity). If you want to avoid this, use a new Object() constructed for just
synchronization purposes as your monitor.

BK
 
R

Razvan

That brings up one very important point one should always remember while using
the wait/ notify mechanism. You should always be prepared for unexpected
notify() calls to arrive when you are "wait()ing". Receiving a notify is not
sufficient indication that a condition that you're looking for has been
satisfied. There is never a guarantee that the super class of the object you
are using as the monitor will not call notify() or notifyAll() on itself during
the execution of some of its instance methods.

Thanks for your answer. Indeed, this seems to be the case:
previously I was synchronizing on an Object and I got the predicted
behavior. Later when I synchronized on a Thread I got the above
mentionated behavior.

That is the reason why the construct

synchronized (object)
{
while (somecondition)
{
object.wait();
}
}

is the most commonly employed one (InterruptedException handling skipped for
clarity). If you want to avoid this, use a new Object() constructed for just
synchronization purposes as your monitor.

You are saying that there are 2 solutions to this problem:

1. use an Object (this will guarantee that you will not receive
unwanted notifications);
2. test for a certain condition in a while loop and each time you
received a notification check the condition; if the condition is not
met then call wait() again;


Thanks again.




Regards,
Razvan
 
B

Babu Kalakrishnan

Razvan said:
You are saying that there are 2 solutions to this problem:

1. use an Object (this will guarantee that you will not receive
unwanted notifications);

2. test for a certain condition in a while loop and each time you
received a notification check the condition; if the condition is not
met then call wait() again;

Even when I use an exclusive object as the monitor, I always tend to use the
latter also (probably out of habit), because in almost all cases where you use
the wait/notify mechanism, the thread that is doing the wait is indeed waiting
for a condition to be satisfied, and it is generally good practice to ensure
that it has been really satisfied before moving along. Basically ensures that
the notify() that you received was meant for your thread and not anyone else.

Helps you in situations where you modify the class at a later stage and added
another section of code that calls notifyAll() on the same object.

Also, it is always good design practice for you code to be not dependent on any
specific behaviour of an object that isn't guaranteed by API contract or a JLS
spec. So if a hypothetical JVM were to call notify() on every object say while
it is examining it for reachability for GC purpose, it would not be breaking any
language rule (I think), and you obviously wouldn't want your code to break if
that happens (however improbable it may be).

BK
 
C

Chris Uppal

Babu said:
Even when I use an exclusive object as the monitor, I always tend to use
the latter also (probably out of habit)

Another reason to do this (why it's a good habit to get into) is that it will
save you lots of time explaining to collegues, etc, /why/ you have choosen to
ignore the standard pattern in this case, and proving to them (time and again)
that it /is/ actually safe in this instance.

And, of course, there are related benefits to maintainability.

-- chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top