/*
 * simple synchronization example, version 3:
 *
 * threads perform I/O with delays, introducing need to ensure one-at-a-time
 *   access to System.out.
 *
 * correct synchronization, one way.
 *
 * command-line argument specifies number of threads.
 */
package csci3366.sample.synch;
import csci3366.sample.utility.Utility;

public class HelloSynch3 {

    /* main method */
    public static void main(String[] args) {

        /* get number of threads from command line */

        int numThreads = Utility.getIntegerArg(args, 0, 1, 
                "numThreads", "arguments:  numThreads");

        /* create threads */

        Thread[] threads = new Thread[numThreads];

        for (int i = 0; i < threads.length; ++i) {
            threads[i] = new Thread(new Inner(i));
        }

        /* start them up */

        System.out.println("starting threads");

        for (int i = 0; i < threads.length; ++i) {
            threads[i].start();
        }

        /* wait for them to finish */

        for (int i = 0; i < threads.length; ++i) {
            try {
                threads[i].join();
            }
            catch (InterruptedException e) {
                System.err.println("should not happen");
            }
        }

        System.out.println("threads all done");
    }

    /* inner class containing code for each thread to execute */

    private static class Inner implements Runnable {

        private int myID;

        public Inner(int myID_) {
            myID = myID_;
        }

        public void run() {
            helloWithDelay(myID);
        }

        /* 
         * "hello with delay" method
         * "static synchronized" means only thread at a time can call
         * the method, period.
         */
        private static synchronized void helloWithDelay(int threadID) {
            System.out.print("hello from thread ");
            try {
                Thread.sleep(10);
            }
            catch (InterruptedException e) {
                System.err.println("should not happen");
            }
            System.out.println(threadID);
        }
    }
}