Threads.java
Download Threads.java
1: /* Threads.java - App to show how to pause and terminate threads
2: * without using stop(), suspend(), or resume().
3: *
4: * Each thread draws a simple animation of the letters of the alphabet
5: * and checks for stop requests only once each cycle, on 'Z'. Suspend
6: * requests are processed immediately. Note the use of synchronized
7: * blocks (and methods) whenever a shared variable is accessed, and
8: * whenever using wait() or notify().
9: *
10: * This program was adapted from RandomCharacters.java, pp. 760-762
11: * of Deitel & Deitel "Java How to Program", 3rd Ed. (C) 1999 by
12: * Prentice-Hall.
13: *
14: * Written 2000 by Wayne Pollock, Tampa Florida USA.
15: * Modified 2021 to convert from Applet.
16: */
17:
18: import java.awt.*;
19: import java.awt.event.*;
20:
21: public class Threads extends Frame implements ItemListener, Runnable {
22: private Thread [] thread;
23: private Label [] output;
24: private Checkbox [] suspendRequest, stopRequest;
25: private boolean [] suspended; // The actual status.
26: private Component me; // Used to hide the focus, which I think is ugly.
27: private static final int NUM_THREADS = 3 + 1;
28:
29: public static void main ( String[] args ) {
30: Frame frame = new Threads();
31: frame.setSize(400, 150);
32: frame.setTitle("Multi-threading Demo");
33: frame.setLocationRelativeTo(null); // Center on screen
34: frame.addWindowListener(new WindowAdapter(){
35: public void windowClosing(WindowEvent e) {
36: frame.dispose();
37: }
38: });
39: frame.setVisible(true);
40: }
41:
42: public Threads () {
43: me = this;
44: stopRequest = new Checkbox[ NUM_THREADS ];
45: suspendRequest = new Checkbox[ NUM_THREADS ];
46: suspended = new boolean[ NUM_THREADS ];
47: thread = new Thread[ NUM_THREADS ];
48: output = new Label[ NUM_THREADS ];
49:
50: // Set up GUI:
51:
52: setLayout( new GridLayout( 0, 3, 5, 5 ) );
53: setBackground( Color.cyan );
54:
55: // For each thread: create, initialize, and add a Label and
56: // Checkboxes for syspend and stop requests.
57:
58: for ( int i = 1; i < NUM_THREADS; ++i )
59: { output[i] = new Label();
60: add( output[i] );
61: output[i].setText( "Thread " + i + ": A" );
62: suspendRequest[i] = new Checkbox( "Suspend" );
63: add( suspendRequest[i] );
64: suspended[i] = false;
65: stopRequest[i] = new Checkbox( "Stop" );
66: add( stopRequest[i] );
67: thread[i] = new Thread( this, "" + i );
68: thread[i].start();
69:
70: // Hook up event listeners for the Checkboxes:
71:
72: suspendRequest[i].addItemListener( this );
73: stopRequest[i].addItemListener( new ItemListener ()
74: { public synchronized void itemStateChanged ( ItemEvent e )
75: { if ( e.getStateChange() == ItemEvent.SELECTED )
76: notifyAll(); // wake up suspended threads (if any).
77: me.requestFocus();
78: }
79: }
80: );
81: }
82: }
83:
84:
85: public synchronized void start ()
86: { for ( int i = 1; i < NUM_THREADS; ++i )
87: suspended[i] = suspendRequest[i].getState();
88: notifyAll();
89: me.requestFocus(); // Hide the focus.
90: }
91:
92:
93: public synchronized void stop ()
94: { for ( int i = 1; i < NUM_THREADS; ++i )
95: suspended[i] = true;
96: }
97:
98: // Handler for suspendRequest events (not stop events):
99:
100: public synchronized void itemStateChanged ( ItemEvent ie )
101: { for ( int i = 1; i < NUM_THREADS; ++i )
102: if ( ie.getSource() == suspendRequest[i] )
103: if ( ! suspendRequest[i].getState() )
104: { suspended[i] = false;
105: notifyAll(); // Wake up all waiting threads (Qu: Why?)
106: } else
107: { suspended[i] = true;
108: }
109: me.requestFocus(); // Hide the focus.
110: }
111:
112:
113: public void run ()
114: { String threadName = Thread.currentThread().getName();
115: int i = 0; // i is the current Thread's index number (its name too).
116: int ch = 'A';
117:
118: try { i = Integer.parseInt( threadName ); }
119: catch ( Exception e )
120: { System.err.println("Cannot parse Thread " + threadName +
121: "\n" + e );
122: }
123:
124: // Note tricky method of sequencing ABC...XYZABC...XYZABC...
125: // Also note how this whole method could be simplified if
126: // Thread-local data were used. Sadly that is not a Java 1.1 feature.
127:
128: MainLoop:
129: for ( ;; )
130: { // Pause for between 0.5 and 1.0 seconds:
131: try { Thread.sleep( 500 + (int) (Math.random() * 500) ); }
132: catch ( InterruptedException e ) {} // Do nothing.
133:
134: synchronized ( this )
135: { if ( ch == 'Z' && stopRequest[i].getState() )
136: break MainLoop; // Time to quit.
137:
138: while ( suspended[i] )
139: { output[i].setBackground( Color.lightGray );
140: try { wait(); } catch ( InterruptedException e ) {}
141: if ( ch == 'Z' && stopRequest[i].getState() )
142: break MainLoop; // stop overrides suspend
143: }
144: output[i].setBackground( Color.cyan );
145: }
146: ch = ( ((ch-'A') + 1) % 26 ) + 'A';
147: output[i].setText( "Thread " + i + ": " + (char) ch );
148: }
149: output[i].setBackground( Color.gray );
150: suspendRequest[i].setEnabled( false );
151: stopRequest[i].setEnabled( false );
152: }
153:
154: } // End of class Threads