Forums Register Login
wait and notify
This example is taken straight from a Java 2 revision for the programmer exam.

1. class ThreadA {
2. public static void main(String [] args) {
3. ThreadB b = new ThreadB();
4. b.start();
6. synchronized(b) {
7. try {
8. System.out.println("Waiting for b to complete...");
9. b.wait();
10. } catch (InterruptedException e) {}
11. }
12. System.out.println("Total is: " + b.total);
13. } // end main
14.} // end Class
16.class ThreadB extends Thread {
17. int total;
19. public void run() {
20. synchronized(this) {
21. for(int i=0;i<100;i++) {
22. total += i;
23. }
24. notify();
25 }
26. }

Basically the main thread waits for b to do a calculation and prints result. The book explains that when b is started, main continues and gets lock on b, enters its synchronized block. Then wait() on b makes it release the lock and wait until b calls notify to tell it its done calculating. Main can then read the data when selected to run again by JVM, having regotten lock for b. And we're hunky dory.

BUT, what happens it b is lightning fast and its run method is called b4 main get lock on b and calls wait etc (ie b4 main gets to its synch block), which can happen as thread execution is indeterminate. b is in its synchronized block with lock on "this", doing the calculation so main cant enter its synch block.
b completes, and calls notify and exits its synch block. So main can now get lock on b and go into its synch block...but it then calls wait() on b expecting to be notified soon of a calculation completion. But b has exited its synch block earlier and notify() will never be called - is main stuck for ever waiting here???(obviously we could pass a timeout to wait() but that wasnt the case in the code in the book)

Yes, main() would be stuck forever waiting. This is called a "race condition", and it happens often in sloppy programs. It's one example of why programming with threads is hard. Congratulations for seeing that it could happen, though -- this means you've got what it takes to be good at it!

Another way to deal with this is to give ThreadB a boolean member variable "completed" which is set to true after the thread is done, and then have main() do something like

Because "completed" is used by multiple threads, it should always be read and updated in synchronized blocks.
Neat question, Tom, and it's exposing some things I don't know.

Would "volatile" be sufficient for a public boolean like "completed"? This looks to be exactly the situation described in what I've read about volatile.

Would join(b) have the same risk as wait() if b happens to finish first?
b.join() in main would put the current thread (ie main) into a waiting state until the thread b completed its run method and died. In that sense main would only the lock on b after its calculation was completed aand b died and main could read the total.
Hence if the calculation is only done once (like in example) then i think b.join() will suffice.

In a more complex case this wont work:
Above b.join() method assumes the calculation is to be done only once ever and now b then dead, after exiting synch block and run. In a real case, I suppose b would repeat the calculation (say downloading stock data or something) via an infinite while loop in the run method.
If the situation arose which i described in my first post, main wouldnt actually get infinitely stuck, i think it would however miss the first calculation result, as it wasnt set up to be waiting when b called notify. So in this scenario of repeated b calculation, join() is no good as main will never run as theres an infinite while loop in b.

Makes good sense. The run() as given does a finite loop and dies, so I thought of join(). If run() were to give periodic results ... ping a web site all day and tell you if the response time is over 2 seconds ... I'd go for some kind of pub-sub and not make A wait on B at all.
Gotta be careful here if you start to experiment. Note that the implementation of join() uses wait/notify on the Thread object itself, and so this program (which also calls Thread.notify() ) will interact with it. In practice, wait()ing on a Thread is quite rare, so this doesn't come up too often -- but it's a real issue.
Stan James:

Would "volatile" be sufficient for a public boolean like "completed"? This looks to be exactly the situation described in what I've read about volatile.

It has been a while since I looked at the specifics, but I believe that with the Java memory model, "volatile" would not have sufficed prior to Java 1.5. I think this may have been fixed in Java 1.5. I may be thinking of "long"s, though, as they are less thread safe due to nonatomic reads and writes of the two halves of the long; or maybe it's that "volatile long"s haven't been fixed even in 1.5.

I always use explicit synchronization rather than relying on "volatile", myself.
Wink, wink, nudge, nudge, say no more ... https://richsoil.com/cards

All times above are in ranch (not your local) time.
The current ranch time is
Oct 22, 2017 03:48:56.