2

First thing i think i should say is that i am not looking for a solution , this is hwk , but it runs correctly , what would help me greatly is come clarification..

We were just introduce to threads in my object oriented programing class , and received an assignment , which I completed. In my code I never call notifyAll() , but it seems as though it is called implicitly before exiting the run(). Another classmate of mine had the same question. I read somewhere that a Thread that is waiting on another Thread is notified ( implicit notifyAll() ?) when the thread it is waiting on dies/exits the run method. here is my code ( the runnable , and the main where it all runs)

if I remove the wait, and the replace the InterruptedException with Throwable , the code runs , but not correctly , the threads appear after their sleep time then print the termination message and die in the order they appear.

I couldnt post a pic so ill do my best to describe how it works: each thread sleeps for the alloted time and holds a Thread array , which holds references to threads it must wait for

ex: T1 arrives at 2 seconds depends T2,T3 T2 arrives at 4 seconds depends on no-one T3 arrives at 6 seconds depends on no-one so... T1 arrives and has to wait for T2 and T3 before it can terminate, T2 and T3 can terminate immediately..

here are the arrival times and who they depend on:

T1 4 sec , no-one T2 6 sec , no-one T3 7 sec , no-one T4 2 sec , T1,T2 T5 3 sec , T3 T6 1 sec , T3,T4 T7 8 sec , T4 T8 5 sec , T6

sorry about the horrendously long explanation , i am not looking for a solution , the code runs properly , i need some clarification on how if wait is called and notify is never called how it runs?

public class TScheduler {




    public static void main(String[] args) {




    long originTime = System.currentTimeMillis();

    // Long.parse.long(args[0]) * 1000
    DepThread t1 = new DepThread(originTime , 4000 , new Thread[]{});
    Thread T1 = new Thread(t1);
    T1.setName("T1");
    // Long.parse.long(args[1]) * 1000
    DepThread t2 = new DepThread(originTime , 6000 , new Thread[]{});
    Thread T2 = new Thread(t2);
    T2.setName("T2");

    DepThread t3 = new DepThread(originTime , 7000 , new Thread[]{});
    Thread T3 = new Thread(t3);
    T3.setName("T3");

    DepThread t4 = new DepThread(originTime , 2000 , new Thread[]{T1,T2});
    Thread T4 = new Thread(t4);
    T4.setName("T4");

    DepThread t5 = new DepThread(originTime , 3000 , new Thread[]{T3});
    Thread T5 = new Thread(t5);
    T5.setName("T5");

    DepThread t6 = new DepThread(originTime , 1000 , new Thread[]{T3,T4});
    Thread T6 = new Thread(t6);
    T6.setName("T6");

    DepThread t7 = new DepThread(originTime , 8000 , new Thread[]{T4});
    Thread T7 = new Thread(t7);
    T7.setName("T7");

    DepThread t8 = new DepThread(originTime ,5000 , new Thread[]{T6});
    Thread T8 = new Thread(t8);
    T8.setName("T8");

    DepThread t9 = new DepThread(originTime , 500 , new Thread[]{T7});
    Thread T9 = new Thread(t9);
    T9.setName("T9");




    T1.start();
    T2.start();
    T3.start();
    T4.start();
    T5.start();
    T6.start();
    T7.start();
    T8.start();
    T9.start();






    }

}




public class DepThread implements Runnable {

    long sleepTime;
    Thread[] depThrdArray;
    public boolean done = false ;
    long baseTime ;

    public DepThread( long baseTime , long arrivalTime ,  Thread[] depThrdArray ){
    //super();
    this.baseTime = baseTime;
    this.sleepTime = arrivalTime;
    this.depThrdArray = depThrdArray;
    this.done = false;
    }

    @Override
    public void run() { 
    try {
        Thread.sleep(sleepTime);
        System.out.println( Thread.currentThread().getName() + " arrived at " + (System.currentTimeMillis() - baseTime));
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    for ( int i = 0 ; i < depThrdArray.length ; i ++){
        if ( depThrdArray[i].isAlive()){
        synchronized(depThrdArray[i]){
            try {
            depThrdArray[i].wait();
            System.out.println(Thread.currentThread().getName() + " waiting on " + depThrdArray[i].getName() 
                + " time " + (System.currentTimeMillis() - this.baseTime));
            } catch (InterruptedException e) {
            e.printStackTrace();
            }
        }
        }

    }

    this.done = true;
    //synchronized (this){
    //    notifyAll();
    //}
    System.out.println(Thread.currentThread().getName() + "  at time " + ( System.currentTimeMillis() -  baseTime) + " terminating");
    }

}
stefan
  • 10,215
  • 4
  • 49
  • 90
spacemonkey
  • 133
  • 1
  • 11
  • This is java, right? you should add the appropriate tag. – stefan Apr 21 '14 at 20:17
  • @Gray There may be a http://en.wikipedia.org/wiki/Spurious_wakeup , but ... that seems to be a rather rare thing ( http://stackoverflow.com/questions/1050592/do-spurious-wakeups-actually-happen ) – Marco13 Apr 21 '14 at 20:33
  • This is true @Marco13. Good point. – Gray Apr 21 '14 at 20:33

1 Answers1

3

Thread calls notifyAll upon termination in support of the join functionality. This is documented in the Javadoc for Thread#join:

This implementation uses a loop of this.wait calls conditioned on this.isAlive. As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances.

There are essentially two conclusions then:

  • If you want to wait until a Thread terminates, use join.
  • If you want to use wait otherwise, do not use a Thread instance as a monitor.
Radiodef
  • 37,180
  • 14
  • 90
  • 125
  • I read the same thing as this gentleman above posted , I thought it may have pertained only to the join() , when I asked my professor , he pretty much brushed me off and said he had never heard of it. I have ran the code as i posted and it runs as per the assignment , if i remove the depThrdArray[i].wait() and change the InterruptedException to Throwable , the code does not run correctly , so , leads me to believe that the wait is be executed.. – spacemonkey Apr 21 '14 at 20:46
  • `notifyAll` is called and I suppose your professor has not read the documentation. If you've got some other uncertainty please edit the question with a [more minimal example](http://stackoverflow.com/help/mcve) that clearly illustrates it. – Radiodef Apr 21 '14 at 20:51
  • 1
    Notice (as mentioned) that this is implementation dependent. Another JVM may not use `notifyAll()` so it should certainly should be considered a hack @user3395349. For another data point, Java 6 does not mention this although that's what happens under the covers: http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html#join(long) – Gray Apr 21 '14 at 21:39
  • I am brand new to Threads, is not good practice to wait on another Thread vs an Object ? For most producer-Consumer examples i have seen there are 2 different extended thread classes that call getSomething or placeSomething methods implemented in a 3rd class that synchs the threads – spacemonkey Apr 21 '14 at 21:52
  • if i un-commented the synchronized block at the end of my code which has the notifyall() , would that eliminate any potential issues? – spacemonkey Apr 21 '14 at 21:58
  • It is recommended to not use `wait`, `notify` and `notifyAll` on Thread instances at all. My answer already states you should use `join` or some other object as the monitor. If there are examples that exhibit `wait` and `notify` on an instance of Thread they are wrong to suggest it. I don't know what you are referring to when you say 'issues'. You cannot depend on the behavior of calling `wait`, `notify` and `notifyAll` on an instance of Thread. To eliminate potential issues, do not use an instance of Thread as a monitor. – Radiodef Apr 21 '14 at 22:21
  • I see what you are saying , i was following the instructions on the hwk , which state we are to wait on an instance of thread. Thank you for your help. – spacemonkey Apr 22 '14 at 14:52