/****************************************
 * 
 * @author Sun
 * Interrupts
*  An interrupt is an indication to a thread 
*  that it should stop what it is doing and do something else. 
*  It's up to the programmer to decide exactly how a thread 
*  responds to an interrupt, but it is very common for 
*  the thread to terminate. This is the usage emphasized 
*  in this lesson.
*  
*  A thread sends an interrupt by invoking interrupt on the 
*  Thread object for the thread to be interrupted. 
*  For the interrupt mechanism to work correctly, the interrupted 
*  thread must support its own interruption. 
*  
*  The join method allows one thread to wait for the completion 
*  of another. If t is a Thread object whose thread is currently executing,

    t.join();

*  causes the current thread to pause execution until t's thread terminates. 
*  Overloads of join allow the programmer to specify a waiting period. 
*  However, as with sleep, join is dependent on the OS for timing, so 
*  you should not assume that join will wait exactly as long as you specify.
*  
*  Like sleep, join responds to an interrupt by exiting with an 
*  InterruptedException. 
*  
*  The following example brings together some of the concepts of this section. 
*  SimpleThreads consists of two threads. The first is the main thread 
*  that every Java application has. The main thread creates a new 
*  thread from the Runnable object, MessageLoop, and waits for 
*  it to finish. If the MessageLoop thread takes too long to 
*  finish, the main thread interrupts it.
*  
*  The MessageLoop thread prints out a series of messages. 
*  If interrupted before it has printed all its messages, 
*  the MessageLoop thread prints a message and exits. 
*
*
 */
public class SimpleThreads {

    //Display a message, preceded by the name of the current thread
    static void threadMessage(String message) {
        String threadName = Thread.currentThread().getName();
        System.out.format("%s: %s%n", threadName, message);
    }

    private static class MessageLoop implements Runnable {
        public void run() {
            String importantInfo[] = {
                "Mares eat oats",
                "Does eat oats",
                "Little lambs eat ivy",
                "A kid will eat ivy too"
            };
            try {
                for (int i = 0; i < importantInfo.length; i++) {
                    //Pause for 4 seconds
                    Thread.sleep(4000);
                    //Print a message
                    threadMessage(importantInfo[i]);
                }
            } catch (InterruptedException e) {
                threadMessage("I wasn't done!");
            }
        }
    }

    public static void main(String args[]) throws InterruptedException {


        //Delay, in milliseconds before we interrupt MessageLoop
        //thread (default one hour).
        long patience = 1000;    //1000 * 60 * 60;

        //If command line argument present, gives patience in seconds.
        if (args.length > 0) {
            try {
                patience = Long.parseLong(args[0]) * 1000;
            } catch (NumberFormatException e) {
                System.err.println("Argument must be an integer.");
                System.exit(1);
            }

        }

        threadMessage("Starting MessageLoop thread");
        long startTime = System.currentTimeMillis();
        Thread t = new Thread(new MessageLoop());
        t.start();

        threadMessage("Waiting for MessageLoop thread to finish");
        //loop until MessageLoop thread exits
        while (t.isAlive()) {
            threadMessage("Still waiting...");
            //Wait maximum of 1 second for MessageLoop thread to
            //finish.
            t.join(1000);
            if (((System.currentTimeMillis() - startTime) > patience) &&
                    t.isAlive()) {
                threadMessage("Tired of waiting!");
                t.interrupt();
                //Shouldn't be long now -- wait indefinitely
                t.join();
            }

        }
        threadMessage("Finally!");
    }
}
