Please send questions to st10@humboldt.edu .

/**
 * ThreadDemo4
 * 
 * a fourth demo for Threads;
 * this one modifies the old Spring 2000 CIS 235 ThreadDemo3.java,
 * making it avoid deprecated Thread methods.
 * It uses an AWT Applet and the Runnable interface, also,
 * but adds "stop" AND "resume" buttons for *each* of the threads;
 *
 * RECOMMENDED SIZE: height 200, width 300
 *
 * modified by: Sharon M. Tuttle
 * last modified: 3-12-01
 **/

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;

public class ThreadDemo4 extends Applet implements Runnable, ActionListener
{
        // threads to be started up within this applet
        Thread  myThread1, myThread2, myThread3;

        Button  suspT1, suspT2, suspT3, resT1, resT2, resT3;

	// let us know whether thread is currently "suspended"
	boolean	thread1Suspended, thread2Suspended, thread3Suspended;

	// can I set ThreadLocal object numIterations here?
	static ThreadLocal numIterations = new ThreadLocal();

        public void init()
        {
                setBackground(Color.lightGray);
                Label describe = new Label("ThreadDemo4: Version 1.0");
                add(describe);
                Label filler = new Label("Spring 2001");
                add(filler);

                suspT1 = new Button("Suspend Thread 1");
                add(suspT1);
                suspT1.addActionListener(this);
                resT1 = new Button("Resume Thread 1");
                add(resT1);
                resT1.addActionListener(this);

                suspT2 = new Button("Suspend Thread 2");
                add(suspT2);
                suspT2.addActionListener(this);
                resT2 = new Button("Resume Thread 2");
                add(resT2);
                resT2.addActionListener(this);

                suspT3 = new Button("Suspend Thread 3");
                add(suspT3);
                suspT3.addActionListener(this);
                resT3 = new Button("Resume Thread 3");
                add(resT3);
                resT3.addActionListener(this);
        }

        // creates and starts up my threads --- is executed every time the
        // user comes into the applet context after moving away?
        public void start()
        {
                // for each of the 3 threads not yet started,
                // start them up
                if (myThread1 == null)
                {
                        // ...start it up for this applet,
                        // naming this thread "My Thread #1"
                        myThread1 = new Thread(this, "My Thread #1");
			thread1Suspended = false;
                        myThread1.start();
                }

                if (myThread2 == null)
                {
                        myThread2 = new Thread(this, "My Thread #2");
			thread2Suspended = false;
                        myThread2.start();
                }

                if (myThread3 == null)
                {
                        myThread3 = new Thread(this, "My Thread #3");
			thread1Suspended = false;
                        myThread3.start();
                }
        }


        // run() is called by the system after thread has been started
        // by the system
        public void run()
        {
                Thread  executingThread;
                String  threadName = "";
		Integer numIts;

                // this will help me to determine the currently-
                // executing thread, for display purposes;
                executingThread = Thread.currentThread();

                while ((myThread1 == executingThread)||
		       (myThread2 == executingThread)||
		       (myThread3 == executingThread))
                {
			System.out.println("This thread is: " +
			executingThread.getName());

			// how many times has this loop iterated
			// for this thread?
			numIts = (Integer) numIterations.get();		
			if (numIts == null)
			{
				numIts = new Integer(1);
			}
			else
			{
				numIts = new Integer(numIts.intValue() + 1);
			}
			numIterations.set(numIts);	

			System.out.println("   its loop iteration: " +
					   numIts);
                        try
                        {
                                // one second pause
                                Thread.sleep(1000);

				// is this where synchronized clause can go?
				// (wait needs to be able to have an InterruptedException
				// caught, so we'll put it in sleep's try-catch, too.)
				synchronized(this)
				{
					while (((myThread1 == executingThread)&&
						(thread1Suspended))
				    	|| ((myThread2 == executingThread) &&
						(thread2Suspended))
		 		    	|| ((myThread3 == executingThread) &&
						(thread3Suspended)))
					{
						wait();
					}
				}			
                        }
                        catch(InterruptedException e)
                        {
                                // no action, but catch is required
                        }
                }
        }

        // suspends execution when the user leaves the page
        public void stop()
        {
                if (myThread1 != null)
                {
			// this is the preferred way to "stop" a
			// thread... set it to null?
			// (note that this *will* stop its
			// while loop in run()!)
			myThread1 = null;
		}
                if (myThread2 != null)
                {
                        // release system resources for that thread
                        myThread2 = null;
                }
                if (myThread3 != null)
                {
                        // release system resources for that thread
                        myThread3 = null;
                }
        }

	// do I need to add synchronized keyword to the method declaration?
        public synchronized void actionPerformed(ActionEvent e)
        {
		String actionCmd;

		actionCmd = e.getActionCommand();

		// handle specified button suspension or resumption
                if (actionCmd.equals("Suspend Thread 1"))
                {
			thread1Suspended = true;
                }
                else if (actionCmd.equals("Suspend Thread 2"))
                {
			thread2Suspended = true;	
                }
                else if (actionCmd.equals("Suspend Thread 3"))
                {
			thread3Suspended = true;
                }
                else if (actionCmd.equals("Resume Thread 1"))
                {
                        thread1Suspended = false;
			notify();	// let waiters know!
                }
                else if (actionCmd.equals("Resume Thread 2"))
                {
			thread2Suspended = false;
			notify();	// let waiters know!
                }
                else if (actionCmd.equals("Resume Thread 3"))
                {
			thread3Suspended = false;
			notify();   // let waiters know!
                }
        }
}