Creating a Threaded Program - Moving into Advanced Topics - Sams Teach Yourself Java in 24 Hours, 7th Edition (2014)

Sams Teach Yourself Java in 24 Hours, 7th Edition (2014)

Part V: Moving into Advanced Topics

Hour 19. Creating a Threaded Program

THIS HOUR’S TO-DO LIST:

Image Use an interface with a program.

Image Create threads.

Image Start, stop, and pause threads.

Image Catch errors.

A computer term used often to describe the hectic pace of daily life is multitasking, which means to do more than one thing at once—such as browsing the Web at your desk while participating in a conference call and doing butt crunch exercises. A multitasking computer is one that can run more than one program at a time.

One sophisticated feature of the Java language is the ability to write programs that can multitask, which is made possible through a class of objects called threads.

Threads

In a Java program, each of the simultaneous tasks the computer handles is called a thread, and the overall process is called multithreading. Threading is useful in animation and many other programs.

Threads are a way to organize a program so it does more than one thing at a time. Each task that must occur simultaneously is placed in its own thread, and this often is accomplished by implementing each task as a separate class.

Threads are represented by the Thread class and the Runnable interface, which are both part of the java.lang package of classes. Because they belong to this package, you don’t have to use an import statement to make them available in your programs.

One of the simplest uses of the Thread class is to slow down how fast a program does something.

Slowing Down a Program

The Thread class has a sleep() method that you can call in any program that should stop running for a short period of time. You often see this technique used in a program that features animation because it prevents images from being displayed faster than the Java interpreter can handle them.

To use the sleep() method, call Thread.sleep() with the number of milliseconds to pause, as in the following statement:

Thread.sleep(5000);

The preceding statement causes the Java Virtual Machine to pause for 5 seconds before doing anything else. If for some reason the JVM can’t pause that long, an InterruptedException is thrown by the sleep() method.

Because this exception might be thrown, you must deal with it in some manner when using the sleep() method. One way to do this is to place the Thread.sleep() statement inside a try-catch block:

try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// wake up early
}

When you want a Java program to handle more than one thing at a time, you must organize the program into threads. Your program can have as many threads as needed, and they all can run simultaneously without affecting each other.

Creating a Thread

A Java class that can be run as a thread is referred to as a runnable (or threaded) class. Although you can use threads to pause a program’s execution for a few seconds, programmers often use them for the opposite reason—to speed up a program. If you put time-consuming tasks in their own threads, the rest of the program runs more quickly. This often is used to prevent a task from slowing down the responsiveness of a program’s graphical user interface (GUI).

For example, if you have written an application that loads stock market price data from disk and compiles statistics, the most time-consuming task is to load the data. If threads are not used in the application, the program’s interface might respond sluggishly as the data is being loaded. This can be extremely frustrating to a user.

Two ways to place a task in its own thread include

Image Putting the task in a class that implements the Runnable interface

Image Putting the task in a class that is a subclass of Thread

To support the Runnable interface, the implements keyword is used when the class is created, as in this example:

public class LoadStocks implements Runnable {
// body of the class
}

When a class implements an interface, it indicates that the class contains some extra behavior in addition to its own methods.

Classes that implement the Runnable interface must include the run() method, which has the following structure:

public void run() {
// body of the method
}

The run() method should take care of the task that the thread was created to accomplish. In the stock-analysis example, the run() method could contain statements to load data from disk and compile statistics based on that data.

When a threaded application is run, the statements in its run() method are not executed automatically. Threads can be started and stopped in Java, and a thread doesn’t begin running until you do two things:

Image Create an object of the threaded class by calling the Thread constructor

Image Start the thread by calling its start() method

The Thread constructor takes a single argument: the object that contains the thread’s run() method. Often, you use the this keyword as the argument, which indicates the current class includes the run() method.

Listing 19.1 contains a Java application that displays a sequence of prime numbers in a text area. In NetBeans, create a new Java file named PrimeFinder, enter the text from the listing in the file, and—wait for it—don’t forget to save it.

LISTING 19.1 The Full Text of PrimeFinder.java


1: package com.java24hours;
2:
3: import java.awt.*;
4: import javax.swing.*;
5: import java.awt.event.*;
6:
7: public class PrimeFinder extends JFrame implements Runnable, ActionListener {
8: Thread go;
9: JLabel howManyLabel;
10: JTextField howMany;
11: JButton display;
12: JTextArea primes;
13:
14: public PrimeFinder() {
15: super("Find Prime Numbers");
16: setLookAndFeel();
17: setSize(400, 300);
18: setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
19: BorderLayout bord = new BorderLayout();
20: setLayout(bord);
21:
22: howManyLabel = new JLabel("Quantity: ");
23: howMany = new JTextField("400", 10);
24: display = new JButton("Display primes");
25: primes = new JTextArea(8, 40);
26:
27: display.addActionListener(this);
28: JPanel topPanel = new JPanel();
29: topPanel.add(howManyLabel);
30: topPanel.add(howMany);
31: topPanel.add(display);
32: add(topPanel, BorderLayout.NORTH);
33:
34: primes.setLineWrap(true);
35: JScrollPane textPane = new JScrollPane(primes);
36: add(textPane, BorderLayout.CENTER);
37:
38: setVisible(true);
39: }
40:
41: public void actionPerformed(ActionEvent event) {
42: display.setEnabled(false);
43: if (go == null) {
44: go = new Thread(this);
45: go.start();
46: }
47: }
48:
49: public void run() {
50: int quantity = Integer.parseInt(howMany.getText());
51: int numPrimes = 0;
52: // candidate: the number that might be prime
53: int candidate = 2;
54: primes.append("First " + quantity + " primes:");
55: while (numPrimes < quantity) {
56: if (isPrime(candidate)) {
57: primes.append(candidate + " ");
58: numPrimes++;
59: }
60: candidate++;
61: }
62: }
63:
64: public static boolean isPrime(int checkNumber) {
65: double root = Math.sqrt(checkNumber);
66: for (int i = 2; i <= root; i++) {
67: if (checkNumber % i == 0) {
68: return false;
69: }
70: }
71: return true;
72: }
73:
74: private void setLookAndFeel() {
75: try {
76: UIManager.setLookAndFeel(
77: "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
78: );
79: } catch (Exception exc) {
80: // ignore error
81: }
82: }
83:
84: public static void main(String[] arguments) {
85: new PrimeFinder();
86: }
87: }


The PrimeFinder application displays a text field, a Display Primes button, and a text area, as shown in Figure 19.1.

Image

FIGURE 19.1 Running the PrimeFinder application.

Most statements in the application are used to create the GUI or display a sequence of prime numbers. The following statements are used to implement threads in this program:

Image Line 7—The Runnable interface is applied to the PrimeFinder class.

Image Line 8—A Thread object variable is created with the name go but isn’t assigned a value.

Image Lines 43–46—If the go object variable has a value of null, which indicates the thread hasn’t been created yet, a new Thread object is created and stored in the variable. The thread is started by calling the thread’s start() method, which causes the run() method of thePrimeFinder class to be called.

Image Lines 49–62—The run() method looks for a sequence of prime numbers beginning with 2, displaying each one in the primes text area component by calling its append() method. The number of primes in the sequence is determined by the value in the howMany text field.

There’s something unusual in the main() method of this application when a PrimeFinder object is created to begin execution of the program. Here’s the statement:

new PrimeFinder();

Normally you’d expect to see that object assigned to a variable, like so:

PrimeFinder frame = new PrimeFinder();

However, because there’s no need to refer to that object again, storing it in a variable is not necessary. Calling new to create the object causes the program to run.

It’s a good programming practice in Java to store objects in variables only when needed.

Working with Threads

You can start a thread by calling its start() method, which might lead you to believe there’s also a stop() method to bring it to a halt.


Caution

It’s a good idea to heed this deprecation warning. Oracle has deprecated the stop() method because it can cause problems for other threads running in the Java interpreter. The resume() and suspend() methods of the class also are deprecated.


Although Java includes a stop() method in the Thread class, it has been deprecated. In Java, a deprecated element is a class, interface, method, or variable that has been replaced with something that works better.

The next project you undertake shows how you can stop a thread. The program you are undertaking rotates through a list of website titles and the addresses used to visit them.

The title of each page and the web address are displayed in a continuous cycle. Users are able to visit the currently displayed site by clicking a button on the application’s graphical user interface. This program operates over a period of time, displaying information about each website in sequence. Because of this time element, threads are the best way to control the program.

Instead of entering this program into the NetBeans source editor first and learning about it afterward, you get a chance to enter the full text of the LinkRotator application at the end of the hour. Before then, each section of the program is described.

The class Declaration

The first thing you need to do in this program is to use import for classes in the packages java.awt, java.io, java.net, java.awt.event, and javax.swing.

After you have used import to make some classes available, you’re ready to begin the application with the following statement:

public class LinkRotator extends JFrame
implements Runnable, ActionListener {

This statement creates the LinkRotator class as a subclass of the JFrame class, like other programs you have developed which feature a graphical user interface. The statement also indicates that two interfaces are supported by this class: Runnable and ActionListener. By implementing the Runnable class, you are able to use a run() method in this program to make a thread begin running. The ActionListener interface enables the program to respond to mouse clicks.

Setting Up Variables

The first thing to do in LinkRotator is create the variables and objects of the class. Create a six-element array of String objects called pageTitle and a six-element array of URI objects called pageLink:

String[] pageTitle = new String[6];
URI[] pageLink = new URI[6];

The pageTitle array holds the titles of the six websites that are displayed. The URI class of objects stores the value of a website address. URI has all the behavior and attributes needed to keep track of a web address.

The last three things to create are an integer variable, a Thread object, and a user interface label:

int current = 0;
Thread runner;
JLabel siteLabel = new JLabel();

The current variable keeps track of which site is being displayed so you can cycle through the sites. The Thread object runner represents the thread this program runs. You call methods of the runner object when you start, stop, and pause the operation of the program.

The Constructor

The program’s constructor automatically is executed when the program is run. This method is used to assign values to the arrays pageTitle and pageLink. It also is used to create a clickable button that appears on the user interface. The method includes the following statements:

pageTitle = new String[] {
"Oracle's Java site",
"Cafe au Lait",
"JavaWorld",
"Java in 24 Hours",
"Sams Publishing",
"Workbench"
};
pageLink[0] = getURI("http://www.oracle.com/technetwork/java");
pageLink[1] = getURI("http://www.ibiblio.org/javafaq");
pageLink[2] = getURI("http://www.javaworld.com");
pageLink[3] = getURI("http://www.java24hours.com");
pageLink[4] = getURI("http://www.samspublishing.com");
pageLink[5] = getURI("http://workbench.cadenhead.org");
Button visitButton = new Button("Visit Site");
goButton.addActionListener(this);
add(visitButton);

The title of each page is stored in the six elements of the pageTitle array, which is initialized using six strings. The elements of the pageLink array are assigned a value returned by the getURI() method, yet to be created.

The last three statements of the init() method create a button labeled “Visit Site” and add it to the application’s frame.

Catching Errors as You Set Up URLs

When you set up a URI object, you must make sure the text used to set up the address is in a valid format: http://workbench.cadenhead.org and http://www.samspublishing.com are valid, but http:www.javaworld.com would not be because of missing / marks.

The getURI(String) method takes a web address as an argument, returning a URI object representing that address. If the string is not a valid address, the method returns null instead:

URI getURI(String urlText) {
URI pageURI = null;
try {
pageURI = new URI(urlText);
} catch (URISyntaxException m) {
// do nothing
}
return pageURI;
}

The try-catch block deals with any URISyntaxLException errors that occur when URI objects are created. Because nothing needs to happen if this exception is thrown, the catch block contains only a comment.

Starting the Thread

In this program, the runner thread starts when its start() method is called.

The start() method is called as the last statement of the constructor. Here’s the method:

public void start() {
if (runner == null) {
runner = new Thread(this);
runner.start();
}
}

This method starts the runner thread if it is not already started.

The statement runner = new Thread(this) creates a new Thread object with one argument: the this keyword. The this keyword refers to the program itself, designating it as the class that runs within the thread.

The call to runner.start() causes the thread to begin running. When a thread begins, the run() method of that thread is called. Because the runner thread is the LinkRotator application itself, the run() method of the application is called.

Running the Thread

The run() method is where the main work of a thread takes place. In the LinkRotator program, the following represents the run() method:

public void run() {
Thread thisThread = Thread.currentThread();
while (runner == thisThread) {
current++;
if (current > 5) {
current = 0;
}
siteLabel.setText(pageTitle[current]);
repaint();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// do nothing
}
}
}

The first thing that takes place in the run() method is the creation of a Thread object called thisThread. A class method of the Thread class, currentThread(), sets up the value for the thisThread object. The currentThread() method keeps track of the thread that’s currently running.

All statements in this method are part of a while loop that compares the runner object to the thisThread object. Both objects are threads, and as long as they refer to the same object, the while loop continues looping. There’s no statement inside this loop that causes the runner andthisThread objects to have different values, so it loops indefinitely unless something outside of the loop changes one of the Thread objects.

The run() method calls repaint(). Next, the value of the current variable increases by one, and if current exceeds 5, it is set to 0 again. The current variable is used to determine which website’s information to display. It is used as the index to the pageTitle array of strings, and the title is set as the text of the siteLabel user interface component.

The run() method includes another try-catch block that handles errors. The Thread.sleep(1000) statement causes a thread to pause 1 second, long enough for users to read the name of the website and its address. The catch statement takes care of anyInterruptedException errors that might occur while the Thread.sleep() statement is being handled. These errors would occur if something interrupted the thread as it slept.

Handling Mouse Clicks

The last thing to take care of in the LinkRotator program is event handling. Whenever a user clicks the Visit Site button, the application should open the displayed website with a web browser. This is done with a method called actionPerformed(), which is called whenever the button is clicked.

The following is the actionPerformed() method of LinkRotator:

public void actionPerformed(ActionEvent event) {
Desktop desktop = Desktop.getDesktop();
if (pageLink[current] != null) {
try {
desktop.browse(pageLink[current]);
runner = null;
System.exit(0);
} catch (IOException exc) {
// do nothing
}
}
}

The first thing that happens in this method is that a Desktop object is created. The Desktop class in the java.awt package represents the desktop environment of the computer running the application. After you have this object, you can use it to launch an email client using a “mailto:” link, open a file for editing with another program, print a file, and make other programs outside of Java perform tasks.

Here, the Desktop object is used to open a web page with the computer’s default web browser.

The browse(URI) method loads the specified web address in a browser. If pageLink[current] is a valid address, browse() requests that the browser load the page.

Displaying Revolving Links

You’re now ready to create the program and test it. Create a new Java file named LinkRotator and type in the text from Listing 19.2.

LISTING 19.2 The Full Text of LinkRotator.java


1: package com.java24hours;
2:
3: import java.awt.*;
4: import java.awt.event.*;
5: import java.io.*;
6: import javax.swing.*;
7: import java.net.*;
8:
9: public class LinkRotator extends JFrame
10: implements Runnable, ActionListener {
11:
12: String[] pageTitle = new String[6];
13: URI[] pageLink = new URI[6];
14: int current = 0;
15: Thread runner;
16: JLabel siteLabel = new JLabel();
17:
18: public LinkRotator() {
19: setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
20: setSize(300, 100);
21: FlowLayout flo = new FlowLayout();
22: setLayout(flo);
23: add(siteLabel);
24: pageTitle = new String[] {
25: "Oracle's Java site",
26: "Cafe au Lait",
27: "JavaWorld",
28: "Java in 24 Hours",
29: "Sams Publishing",
30: "Workbench"
31: };
32: pageLink[0] = getURI("http://www.oracle.com/technetwork/java");
33: pageLink[1] = getURI("http://www.ibiblio.org/javafaq");
34: pageLink[2] = getURI("http://www.javaworld.com");
35: pageLink[3] = getURI("http://www.java24hours.com");
36: pageLink[4] = getURI("http://www.samspublishing.com");
37: pageLink[5] = getURI("http://workbench.cadenhead.org");
38: Button visitButton = new Button("Visit Site");
39: visitButton.addActionListener(this);
40: add(visitButton);
41: setVisible(true);
42: start();
43: }
44:
45: private URI getURI(String urlText) {
46: URI pageURI = null;
47: try {
48: pageURI = new URI(urlText);
49: } catch (URISyntaxException ex) {
50: // do nothing
51: }
52: return pageURI;
53: }
54:
55: public void start() {
56: if (runner == null) {
57: runner = new Thread(this);
58: runner.start();
59: }
60: }
61:
62: public void run() {
63: Thread thisThread = Thread.currentThread();
64: while (runner == thisThread) {
65: current++;
66: if (current > 5) {
67: current = 0;
68: }
69: siteLabel.setText(pageTitle[current]);
70: repaint();
71: try {
72: Thread.sleep(1000);
73: } catch (InterruptedException exc) {
74: // do nothing
75: }
76: }
77: }
78:
79: public void actionPerformed(ActionEvent event) {
80: Desktop desktop = Desktop.getDesktop();
81: if (pageLink[current] != null) {
82: try {
83: desktop.browse(pageLink[current]);
84: runner = null;
85: System.exit(0);
86: } catch (IOException exc) {
87: // do nothing
88: }
89: }
90: }
91:
92: public static void main(String[] arguments) {
93: new LinkRotator();
94: }
95: }


Figure 19.2 shows two windows open on a computer desktop. The smaller window, which is circled, is the LinkRotator application running. The larger one behind is one of the links that can be opened with the program: the web page for Sams, the publisher of this book.

Image

FIGURE 19.2 Displaying revolving links in an application.

Stopping a Thread

The LinkRotator application does not have a way to stop the thread, but it has been designed in a way that would make it simple to do so. Here’s one method that could be called to end execution of the thread:

public void stop() {
if (runner != null) {
runner = null;
}
}

The if statement tests whether the runner object is equal to null. If it is, there isn’t an active thread that needs to be stopped. Otherwise, the statement sets runner equal to null.

Setting the runner object to a null value causes it to have a different value than the thisThread object. When this happens, the while loop inside the run() method stops running.

Summary

Threads are a powerful concept implemented with a small number of classes and interfaces in Java. By supporting multithreading in your programs, you make them more responsive and can speed up how quickly they perform tasks.

Even if you learned nothing else from this hour, you now have a new term to describe your frenzied lifestyle. Use it in a few sentences to see if it grabs you:

Image “Boy, I was really multithreading yesterday after we held up that string of liquor stores.”

Image “I multithreaded all through lunch, and it gave me gas.”

Image “Not tonight, dear, I’m multithreading.”

Workshop

Q&A

Q. Are there any reasons to do nothing within a catch statement, as the LinkRotator application does?

A. It depends on the type of error or exception being caught. In the LinkRotator application, you know with both catch statements what the cause of an exception would be, so you can be assured that doing nothing is always appropriate. In the getURI() method, theURISyntaxException only would be caused if the URI sent to the method is invalid.

Q. Whatever happened to the band that sang “My Future’s So Bright, I Gotta Wear Shades”?

A. Their future was not bright. Timbuk3, a band formed by husband and wife Pat and Barbara K. MacDonald, never had another hit after the song that became a top 20 single in 1986. They produced six albums from 1986 to 1995, when they broke up the band and divorced.

Pat MacDonald continues to perform and release albums under his own name. He’s also written songs for Cher, Peter Frampton, Night Ranger, Aerosmith, and other musicians.

Barbara Kooyman performs as Barbara K and has several albums, one that reinterprets Timbuk3 songs. She also formed the artist’s free speech charity Artists for Media Diversity.

Their best known song, widely taken to be a positive message about the future, was supposed to be ironic. The MacDonalds said the bright future was actually an impending nuclear holocaust.

Quiz

Set aside your threads (in the Java sense, not the nudity sense) and answer the following questions about multithreading in Java.

1. What interface must be implemented for a program to use threads?

A. Runnable

B. Thread

C. No interface is required

2. If an interface contains three different methods, how many of them must be included in a class that implements the interface?

A. None of them.

B. All of them.

C. I know, but I’m not telling.

3. You’re admiring the work of another programmer who has created a program that handles four simultaneous tasks. What should you tell him?

A. “I’d buy that for a dollar.”

B. “You’re the wind beneath my wings.”

C. “Nice threads!”

Answers

1. A. Runnable must be used with the implements statement. Thread is used inside a multithreaded program, but it is not needed in the class statement that begins a program.

2. B. An interface is a guarantee that the class includes all the interface’s methods.

3. C. This compliment could be confusing if the programmer is well dressed, but let’s be honest, what are the chances of that?

Activities

If this hour’s material hasn’t left you feeling threadbare, expand your skills with the following activities:

Image Create a new version of the LinkRotator application and six of your own favorite websites.

Image Add a button to the PrimeFinder application that can stop the thread while the sequence of prime numbers is still being calculated.

To see Java programs that implement these activities, visit the book’s website at www.java24hours.com.