Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

Java threads question

Options
  • 11-06-2012 12:40pm
    #1
    Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,092 Mod ✭✭✭✭


    public class Reader extends Thread {
    	Calculator c;
    	
    	public Reader(Calculator calc) {
    		c = calc;
    	}
    	
    	public void run() {
    		synchronized(c) {
    		 try {
    			 System.out.println("Waiting for calculation...");
    			 c.wait();
    		 } catch (InterruptedException e) {}
    		
    		 System.out.println("Total is: " + c.total);
    		}
    	 }
    	
    	 public static void main(String [] args) {
    		 Calculator calculator = new Calculator();
    		 new Reader(calculator).start();
    		 new Reader(calculator).start();
    		 new Reader(calculator).start();
    		 calculator.start();
    	}
    }
    	
    class Calculator extends Thread {
    	int total;
    	
    	public void run() {
    		synchronized(this) {
    		 for(int i=0;i<100;i++) {
    			 total += i;		
    		 }
    		//notifyAll();
    	 }
    }
    }	
    
    Waiting for calculation...
    Waiting for calculation...
    Waiting for calculation...
    Total is: 4950
    Total is: 4950
    Total is: 4950
    How come if I remove notifyAll();
    The output is the same?

    Three threads running on an instance, one thread gets a lock on the object, so 2 threads should be waiting?
    Thread finishes it's calculation and releases lock? So if we don't or do notifyAll() the same thing happens?
    If we don't the JVM just schedules the threads and runs them?


Comments

  • Registered Users Posts: 1,414 ✭✭✭Fluffy88


    You've got the right idea and the code works as you would expect.
    All four threads (three Readers and the Main thread) block when trying to execute the sync parts correctly.

    The part about the notifyAll I had a little bit of a look into it earlier and from what I can tell it seems notify is indirectly being called by something, hence why your getting the same outcome with it commented out. As far as I can tell it's right after the sync loop finishes the compiler must inject a call to notify the waiting threads.

    I was going to check it out to try prove it but I was at work and I kinda should have been working on what they pay me to do so I stopped :)

    Sorry I can't be more help, but I'm no thread expert!


  • Registered Users Posts: 1,082 ✭✭✭Feathers


    From my understanding of your code, when the loop finishes, then thread #1 exits, so another gets switched it. Finding itself non-blocked it takes the lock & does it's loop.

    If you did notifyAll() it would wake both #2 & #3 when one exits and the first one to the lock would go next, setting the other to wait.

    Not 100%, again, no thread expert!


  • Registered Users Posts: 89 ✭✭tehjimmeh


    Stackoverflow thread on this here: http://stackoverflow.com/questions/9030526/does-java-notify-waiting-threads-implicitly

    Look at the javadoc for wait():
    A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops, like this one:
         synchronized (obj) {
             while (<condition does not hold>)
                 obj.wait(timeout);
             ... // Perform action appropriate to condition
         }
    
    http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#wait(long)

    So the real answer here is that you're not using wait() correctly, it should always be in the body of a loop which checks a locking condition, as spurious wakeups are a documented possibility.

    The answer to why this behaviour occurs, however, is that, although not documented, or at least not documented in an easy to find place, it seems that Thread is implemented to cause some kind of notification to waiting threads when run() returns. It's perhaps not a spurious wakeup in the usual sense of the phrase, but as spurious wakeups are allowable, it is a behaviour which is acceptable.


  • Moderators, Technology & Internet Moderators Posts: 1,334 Mod ✭✭✭✭croo


    Feathers wrote: »
    From my understanding of your code, when the loop finishes, then thread #1 exits, so another gets switched it. Finding itself non-blocked it takes the lock & does it's loop.

    If you did notifyAll() it would wake both #2 & #3 when one exits and the first one to the lock would go next, setting the other to wait.

    Not 100%, again, no thread expert!
    That's my understanding too. When the run() ends so does the life of the thread. The ending of the thread results in somehting similiar to the notifyAll() hence you see the same thing if notifyAll() is commented or not.


  • Registered Users Posts: 1,414 ✭✭✭Fluffy88


    The first answer from that stackoverflow thread hits the nail on the head.
    Just tested out switching from extending Thread to implementing Runnable and it works perfectly.
    Or you could do as the answer suggested and use a dummy lock object.


  • Advertisement
  • Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,092 Mod ✭✭✭✭Tar.Aldarion


    Thanks guys, that's great. Really appreciate the answers! The book made it seem like leaving it out should make a massive difference.

    I'll mess around with this dummy lock and try to make that work.


Advertisement