Multithreaded Applets

Multithreading in applets is no different than multithreading in apps. (Chapter 10, The WFC app Package, discussed multithreading in apps.)

A Quick Review of Java Multithreading

Without access to the Windows Foundation Classes for Java (WFC), an applet can start a new thread in two ways. The first technique is for you to create a new class that extends the class Thread. The new class must provide a method named run(), which executes in a new thread when the parent class invokes the start() method.

class MyApplet extends Applet
{
 public void init()
 {
 // include initForm() and other applet methods
 }
 /**
 * Start a new thread.
 */
 public void startThread()
 {
 // create an object of class MyThread
 Thread myThread = new MyThread();
 // now start the thread
 // the new thread begins execution with run()
 myThread.start();
 }
}
class MyThread extends Thread
{ /**
 * Execution of the new thread begins here.
 */
 public void run()
 {
 .
 .
 .
 } }


The second approach to multithreading is to create a Thread object from an object that implements the Runnable interface. The object that implements the Runnable interface can be the applet object itself, as shown in the following example, MyApplet. The only requirement of the Runnable interface is the existence of the run() method.

// MyApplet implements Runnable by providing a run() method class MyApplet extends Applet implements Runnable
{
 public void init()
 {
 // include initForm() and other applet methods
 }
 /**
 * Start a new thread.
 */
 public void startThread()
 {
 // create an object of class Thread using this, an object
 // of class MyApplet that implements Runnable
 Thread myThread = new Thread(this);
 // now start the thread.
 myThread.start();
 }
 /**
 * Execution of the new thread begins here.
 */
 public void run()
 { .
 .
 .
 } }


Here we see that since MyApplet implements the Runnable interface, its run() method can become the starting point for a new thread.

MultiThread Prime Number Applet

used the example of a prime number generator to demonstrate multithreading in MS Visual J Plus Plus v6 apps. Let's rewrite the same program here as an applet named MultiThreadApplet to highlight the similarities and the differences between multithreading in apps and multithreading in applets.

problem

The problem is to create an applet that will spawn two independent threads, each of which will calculate prime numbers. The output of these prime numbers will be displayed in different panels within a single frame.

setup work

Create an empty project by choosing New Project from the File menu. Select the Visual J Plus Plus Projects folder, and then select Empty Project. Name the applet MultiThreadApplet, and choose Open.

Add the applet .java file to your empty project by choosing Add Item from the Project menu and adding a class file named MultiThreadApplet.java. We'll also need a class that implements our prime number calculating thread. Repeat the process to add a class file named PrimeThread.java to our project.

Finally, add the HTML file. Select the Add Item command again. This time, select the Page option from the Web Page folder. Before choosing Open, enter the file name MultiThreadApplet.htm.

Applet Frames


The use of frames in an applet is a technique that we have not seen before. In the applet examples we've seen so far—those in Chapter 14, Applets—all output has been to the applet window. In these cases, the Applet object appears (as much as possible) to be a part of the HTML page. To accomplish this functionality, however, the Applet class has to give up some important capabilities. For example, the applet window can't be resized, minimized, or closed.

The Frame class provides the same capabilities as the app Form class does. In contrast to an Applet object, a Frame object has a title bar that supports minimizing, maximizing, and closing. In addition, the frame boundary supports resizing. The downside of frames is that they are not part of the HTML page. Instead, frames hover over the HTML page. In fact, the user can grab the frame and drag it completely outside the browser window. The only connection between a frame and the HTML page that spawns it is that when the HTML page is closed, the frame closes.

A frame can be used in any applet, and is most commonly used to create a dialog box. There is no connection between a frame and multithreading. However, using a frame enables the applet to look more like the multithreaded app it's mimicking.

PrimeThread code

The key to this applet lies in the PrimeThread class code, which extends a Thread class and is designed to calculate and display prime numbers:

import java.awt.*;
/**
 * Thread that calculates primes and reports
 * them to output control.
 */
public class PrimeThread extends Thread
{
 // number of primes
 int numberOfPrimes = 0;
 // display controls
 TextField output = new TextField();
 Panel panel = new Panel();
 /**
 * Initialize the prime number thread.
 */
 public PrimeThread(String name, int priority)
 {
 // create a label object with the name
 Label label = new Label(name);
 // make the output control read only
 output.setEditable(false);
 // set the current thread's priority
 this.setPriority(priority);
 // -----format the thread's display panel-------
 // put space around the outside
 panel.setLayout(new BorderLayout());
 panel.add("West", new Label(" "));
 panel.add("East", new Label(" "));
 panel.add("North",new Label(" "));
 panel.add("South",new Label(" "));
 // create an inner panel with the label and // the output text field and put it in the center
 // of the panel
 Panel innerPanel = new Panel();
 innerPanel.setLayout(new BorderLayout());
 innerPanel.add("North", label);
 innerPanel.add("South", output);
 panel.add("Center", innerPanel);
 }
 /**
 * Return the panel that contains the prime number
 * thread's output.
 */
 Panel getPanel()
 {
 return panel;
 }
 /**
 * Return true if number is prime.
 * * @param number - the number to test
 */
 boolean isPrime(long number)
 {
 // test all the multiples from 2 to the
 // square root of the number (increment
 // to handle potential round-off problems)
 long max = (long)Math.sqrt(number) + 1;
 for (long test = 2; test <= max; test++)
 {
 // if number is evenly divisible by test…
 long remainder = number % test;
 if (remainder == 0)
 {
 // it can't be prime
 return false;
 }
 }
 // made it through, it must be prime
 return true;
 }
 /**
 * Start the background PrimeThread class executing.
 */
 public void run()
 {
 // keep calculating prime numbers
 // until we wrap around
 for (long i = 0; i >= 0; i++)
 {
 try
 {
 // give up control
 Thread.yield();
 // now calculate a new prime
 if (isPrime(i))
 {
 // count it
 numberOfPrimes++;
 // output prime number to the control
 // specified
 output.setText("#" +
 toString(numberOfPrimes) +
 "- " +
 toString(i));
 }
 }
 // ignore any exceptions that might occur
 catch(Exception e)
 {
 }
 }
 }
 /**
 * Convert a number into a string with commas.
 */
 private String toString(long value)
 {
 // convert the long into a string
 String s = Long.toString(value);
 // now add commas to that string
 StringBuffer sb = new StringBuffer(20);
 int offset = 0;
 for(int length = s.length();
 length > 0;
 length--)
 {
 // every 3 digits from the right side…
 if ((length % 3) == 0)
 {
 // but not at the beginning…
 if (offset != 0)
 {
 // put a comma
 sb.append(',');
 }
 }
 // now add another digit
 sb.append(s.charAt(offset++));
 }
 return sb.toString();
 }
}


The constructor for the PrimeThread class takes two arguments. The first argument is the name to be displayed in the thread's output panel. The second argument is the priority of the thread. The PrimeThread() constructor begins by creating a Label object out of the name passed to it. The constructor continues by setting the properties of the newly created output text field. This text field will be used to display the prime numbers as they are calculated. Next the constructor sets the priority for the current thread. The remainder of the PrimeThread() constructor is spent laying out the label and text field objects within a newly constructed panel.

The getPanel() method returns a reference to the panel that is created by the constructor. The remainder of the methods, isPrime(), run(), and toString(), are identical to the methods of the same name in the MultiThreadApplet app in .

MultiThreadApplet code

The code for the MultiThreadApplet class appears as follows:

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
/**
 * This class implements the MultiThreadApplet (prime number)
 * app example from  as an applet.
 */
public class MultiThreadApplet extends Applet
{
 // frame will be used to house the prime number threads' output
 Frame frame;
 // the two prime number threads (PrimeThread extends Thread)
 PrimeThread pt1;
 PrimeThread pt2;
 /**
 * Create and lay out the display objects.
 */
 public void start()
 {
 // create two thread objects (one with a lower priority
 // than the other); the class PrimeThread also creates the
 // output panels, including display objects
 pt1 = new PrimeThread("Prime #1", Thread.NORM_PRIORITY);
 pt2 = new PrimeThread("Prime #2", Thread.NORM_PRIORITY - 1);
 // display both panels created by PrimeThead in a frame
 frame = new Frame("Applet Prime Number");
 frame.setLayout(new BorderLayout());
 frame.add("North", pt1.getPanel());
 frame.add("South", pt2.getPanel());
 // now display the frame
 frame.setSize(300, 200);
 frame.setResizable(false);
 frame.setVisible(true);
 // the following listener is invoked when the user clicks
 // the frame's close button
 frame.addWindowListener(new FrameCloseAdapter());
 // start the two threads executing
 pt1.start();
 pt2.start();
 }
 // the following adapter is invoked when the user clicks // any of the window dressings
 class FrameCloseAdapter extends WindowAdapter
 {
 /**
 * Handle the window close event.
 */
 public void windowClosing(WindowEvent e)
 {
 // kill the threads
 stop();
 }
 }
 /**
 * Kill the two threads, and return their memory to the heap.
 */
 public void stop()
 {
 // if the frame hasn't already been closed…
 if (frame != null)
 {
 // close the frame, dispose of its
 // resources (returns memory to the heap)…
 frame.setVisible(false);
 frame.dispose();
 // and terminate the two threads
 pt1.stop();
 pt2.stop();
 }
 frame = null;
 pt1 = null;
 pt2 = null;
 }
}


The class MultiThreadApplet extends the Applet class, just like in all other applets. Unlike other applets, however, this applet uses the start() method to create the display objects rather than the init() method. This is a result of the fact that MultiThreadApplet must have a stop() method.

The MultiThreadApplet class needs a stop() method because when the browser continues to other HTML pages, the PrimeThread-based threads should be terminated and the frame closed. To accomplish this, we need a stop() method to call Thread.stop() for each of the threads. In addition, stop() closes the frame by calling Frame.setVisible(false) and disposes of the frame's memory by calling Frame.dispose().

If the user returns to the MultiThreadApplet HTML page, the start() method must rebuild the frame and PrimeThread objects. This replaces the objects disposed of by stop().

After creating the two threads of class PrimeThread, the start() method creates a frame with the title "Applet Prime Number" in the title bar. The start() method then creates two panels associated with these two threads and positions them in the top and bottom of the frame. The frame is then resized and displayed.

Finally, start() associates the method windowClosing() with the window close event through the listener FrameCloseAdapter. The windowClosing() method is invoked when the user clicks the close button in the frame's title bar. This method calls stop(), which stops the threads and disposes of the frame. Setting frame to null in the stop() method keeps the applet from attempting to dispose of the frame twice, which it would try to do were the user to close the applet window and then link to another HTML page. This precaution allows the user to click the close button to close the frame rather than forcing him or her to link to another HTML page to close the frame.

Window adapters

Notice that the object passed to addWindowListener() is an object of class FrameCloseAdapter. Based on our previous experience, you would expect that FrameCloseAdapter would implement the WindowListener interface. Instead, FrameCloseAdapter extends the WindowAdapter class. What's going on?

The WindowAdapter class implements the WindowListener interface. By extending this class, FrameCloseAdapter also implements WindowListener. However, the WindowListener interface includes six other methods besides windowClosing(). These methods handle other window-related events such as window minimizing (iconifying) and restoring (deiconifying).

With so many methods in the interface, the programmer is able to handle a number of different events; however, it also makes implementing the WindowListener interface monotonous. Because we don't care about the other six methods, we would need to create six empty "do nothing" methods along with windowClosing() to fully implement WindowListener. To avoid this unnecessary work, Java provides the class WindowAdapter. This class implements the WindowListener interface by providing all seven methods, each of which does nothing. FrameCloseAdapter extends WindowAdapter and overrides the single method windowClosing() with a method that actually does something. FrameCloseAdapter inherits the remaining methods necessary to implement WindowListener.

HTML file

The HTML for MultiThreadApplet is conventional, with the exception of the size of the applet window. The <OBJECT> tag sets the size to 1 by 1 pixel, which essentially makes the applet invisible. (Setting the size to 0 by 0 pixels makes some browsers do strange things.)

<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0">
<TITLE></TITLE>
</HEAD>
<BODY>
<HR>
The prime number applet opens a new form for display.
<P>
<OBJECT CODE="MultiThreadApplet.class"
 HEIGHT=1
 WIDTH=1 VIEWASTEXT>
</OBJECT>
<HR>
</BODY>
</HTML>


result

The MultiThreadApplet program, when run from Microsoft Internet Explorer, results in the output shown in Figure 15-1. The upper output text field of the frame updates rapidly with newly calculated prime numbers, while the lower text field updates much more slowly. What isn't obvious from Figure 15-1 is that the user can drag the prime number frame around in the screen. In addition, the applet frame has its own button on the Microsoft Windows taskbar.

When the user links to a new HTML page, the prime number output frame and the frame's button on the taskbar both disappear immediately. When the user returns to the page, the frame reappears and the threads begin running again. Similar results are obtained when the HTML page is displayed with the HTML editor.

NOTE
I defined the frame so that it's not resizeable by calling the method Frame.isResizable(false). I did this because Visual J++ 6 has a bug in the Frame code. Resizing the frame while the PrimeThread methods are running causes the MultiThreadApplet applet to hang.

Java Click to view at full size.

Screenshot-1. The output from MultiThreadApplet resembles that of the earlier multithreaded apps.

Comments