Demonstrating the runnable interface

  import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;

 public class RandomCharacters extends JApplet implements Runnable, ActionListener 
 {
	 private String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	 private JLabel outputs[];
	 private JCheckBox checkboxes[];
	 private final static int SIZE = 3;

	 private Thread threads[];
	 private boolean suspended[];

	 public void init()
	 {
		 outputs = new JLabel[ SIZE ];
		 checkboxes = new JCheckBox[ SIZE ];
		 threads = new Thread[ SIZE ];
		 suspended = new boolean[ SIZE ];

		 Container c = getContentPane();
		 c.setLayout( new GridLayout( SIZE, 2, 5, 5 ) );

		 for ( int i = 0; i < SIZE; i++ ) 
		 {
			 outputs[ i ] = new JLabel();
			 outputs[ i ].setBackground( Color.green );
			 outputs[ i ].setOpaque( true );
			 c.add( outputs[ i ] );

			 checkboxes[ i ] = new JCheckBox( "Suspended" );
			 checkboxes[ i ].addActionListener( this );
			 c.add( checkboxes[ i ] );
		 }
	}

	 public void start()
	 {
		 // create threads and start every time start is called
		 for ( int i = 0; i < threads.length; i++ ) 
		 {
			 threads[ i ] = new Thread( this, "Thread " + (i + 1) );
			 threads[ i ].start();
		 }
	 }

	 public void run()
	 {
		 Thread currentThread = Thread.currentThread();
		 int index = getIndex( currentThread );
		 char displayChar;

		 while ( threads[ index ] == currentThread ) 
		 {
			 // sleep from 0 to 1 second
			 try 
			 {
				 Thread.sleep( (int) ( Math.random() * 1000 ) );

				 synchronized( this ) 
				 {
					 while ( suspended[ index ] && threads[ index ] == currentThread )
					 wait();
				 }
			 }
			 catch ( InterruptedException e ) 
			 {
				 System.err.println( "sleep interrupted" );
			 }

			 displayChar = alphabet.charAt( (int) ( Math.random() * 26 ) );
			 outputs[ index ].setText( currentThread.getName() +
			 ": " + displayChar );
		 }

		 System.err.println( currentThread.getName() + " terminating" );
	 }

	 private int getIndex( Thread current )
	 {
		 for ( int i = 0; i < threads.length; i++ )
			 if ( current == threads[ i ] )
				 return i;

		 return -1;
	 }

	 public synchronized void stop()
	 {
		 // stop threads every time stop is called
		 // as the user browses another Web page
		 for ( int i = 0; i < threads.length; i++ )
			 threads[ i ] = null;

		 notifyAll();
	 }

	 public synchronized void actionPerformed( ActionEvent e )
	 {
		 for ( int i = 0; i < checkboxes.length; i++ ) 
		 {
			 if ( e.getSource() == checkboxes[ i ] ) 
			 {
				 suspended[ i ] = !suspended[ i ];

				 outputs[ i ].setBackground( !suspended[ i ] ? Color.green : Color.red );

				 if ( !suspended[ i ] )
				 notify();

				 return;
			 }
		 }
	 }
 }
