solvator
solvator

Reputation: 369

How to understand this simple example of thread?

it is an example about wait() and notify() in Java Concurrency. My theory knowledge about it doesn't explain me about this code and I cannot explain why this gives me a misunderstood result.

So, This is code to get an idea:

public class ExampleOne {
    public static void main(String[] args) {
        Test b = new Test();
        b.start();
        synchronized(b){
           try{    
              b.wait();
           } catch(InterruptedException ex){
              ex.printStackTrace();
           }
           System.out.println(b.total);
        }
    }
}

class Test extends Thread {
    int total;

    @Override
    public void run(){
        synchronized(this){
            for(int i =0;i<50;i++){
                total+=i;
                System.out.println("I am here");
            }
            notify();
        }
    } 
}

The result is : 4950

So, how to understand this process (how total can be 4950)?

I understand that If I call wait() it stops the object's thread which called this method and woken up it then another thread calls notify(). Also, synchronized() block restricts threads and accept only one thread in one time.

I am confused about this. Help me to figure it out.

Upvotes: 0

Views: 87

Answers (2)

JB Nizet
JB Nizet

Reputation: 691993

To complement Gray's excellent answer, here's what happens:

main thread:

---------------------------------------------------->
|                   |                            |
start Test thread   waits until notified         wakes up and prints the result

Test thread:

                         ------------------------>
                         |                     |
                         starts running        notifies main thread
                         computes the sum

Also note that it's generally considered bad practice to call wait() and notify() on a Thread instance. A shared object, acting as a lock, should be used instead. notifyAll() should be preferred generally, or even better, a higher-level abstraction like a CountDownLatch should used.

Upvotes: 2

Gray
Gray

Reputation: 116908

If I call wait() it stops the object's thread which called this method and woken up it then another thread calls notify()

Right. notify() or notifyAll() on the same object instance will awaken the thread.

So when thread calls notify(), it becomes non-active until other thread calls wait()?

No. Notify just signals a thread that is waiting on the same object. The thread that calls notify() continues running and does not release the synchronized lock that it is holding.

How wait() and notify() play it's role in this code?

Without wait/notify. the main thread would not wait for the calculation to finish so would probably print 0.

Also synchronized() block?

When you use wait() or notify() you need to be in a synchronized block. It is the monitor associated with the object instance that you are synchronized on that is being waited on and being notified. Also, the synchronized block ensures memory synchronization so the main threads sees the changes to the notify field. Each thread has a memory cache and there needs to be mechanisms in place for threads to publish their changes and see changes to fields made by other threads.

So, how many threads are created in this code?

1 thread is created by your code and the main thread is created automagically by the JVM.

It is important to realize that there is a race condition in this code. It is possible for the new thread to start up, spin through the loop, call notify and exit before the main thread actually calls wait. This is unlikely because starting a thread takes some time but it could happen. In that case, the main thread would be stuck in wait forever because there is no one there to notify it.

Couple other comments:

  • I recommended that you use this.notify(). It's always good to reiterate what is being notified.
  • As @JBNizet points out, it is better to use a private final lock object as opposed to a Thread object.
  • It is always recommended to define a class that implements Runnable as opposed to extending thread. Then you would do new Thread(new TestRunnable()); ....

Upvotes: 5

Related Questions