Extending the Thread Class
A class can also extend the Thread class to create a thread. A typical procedure for doing this is as follows (see Figure 22.3):
- A concrete or an anonymous class extending the Thread class overrides the run() method from the Thread class to define the code executed by the thread.
- This subclass may call a Thread constructor explicitly in its constructors to initialize the thread, using the super() call.
- The start() method inherited from the Thread class is invoked on an object of the class to make the thread eligible for running. This method should never be overridden.
Figure 22.3 Spawning Threads—Extending the Thread Class
The simple example below shows an anonymous class that extends the Thread class and overrides the run() method from the Thread superclass. The code will create a thread and start the thread:
(new Thread() {
@Override
public void run() {
System.out.println(“Harmonious threads create beautiful applications.”)
}
}
).start();
In Example 22.2, the Counter class from Example 22.1 has been modified to illustrate creating a thread by extending the Thread class. The program output shows that the Client class creates two threads and exits, but the program continues running until the child threads have completed execution. The two child threads are independent, each having its own counter and executing its own run() method. Again note that the main thread finished execution before the child threads, but the JVM does not terminate before the child threads are done.
The Thread class implements the Runnable interface, which means that this approach is not much different from implementing the Runnable interface directly. The main difference is that the roles of the Runnable object and the Thread object are combined in a single object by extending the Thread class.
In the previous two examples, the code to create the Thread object, to set the thread name, and to call the start() method to initiate the thread execution is in the client code. In Example 22.2, however, setting the name and starting the thread can be placed in the constructor of the Counter subclass, as it inherits from the Thread class—an exercise the studious reader is encouraged to undertake.
Example 22.2 Extending the Thread Class
public class Counter extends Thread {
public int currentValue;
public Counter() { this.currentValue = 0; }
public int getValue() { return this.currentValue; }
@Override
public void run() { // (1) Override from superclass.
while (this.currentValue < 5) {
System.out.printf(“%s: %s%n”,
super.getName(), // (2) Print thread name,
this.currentValue++); // current value, and increment.
try {
Thread.sleep(500); // (3) Current thread sleeps.
} catch (InterruptedException e) {
System.out.println(super.getName() + ” interrupted.”);
}
}
System.out.println(“Exiting ” + super.getName());
}
}
public class Client {
public static void main(String[] args) {
String threadName = Thread.currentThread().getName(); // (4)
System.out.println(“Method main() runs in thread ” + threadName);
// Create two Counter objects that extend the Thread class: (5)
Counter counterA = new Counter();
Counter counterB = new Counter();
// Set the names for the two threads: (6)
counterA.setName(“Counter A”);
counterB.setName(“Counter B”);
// Mark the threads as daemon threads: (7)
// counterA.setDaemon(true);
// counterB.setDaemon(true);
// Start the two threads: // (8)
System.out.println(“Starting ” + counterA.getName());
counterA.start();
System.out.println(“Starting ” + counterB.getName());
counterB.start();
System.out.println(“Exiting ” + threadName);
}
}
Probable output from the program:
Method main() runs in thread main
Starting Counter A
Counter A: 0
Starting Counter B
Exiting main
Counter B: 0
Counter A: 1
Counter B: 1
Counter B: 2
Counter A: 2
Counter A: 3
Counter B: 3
Counter A: 4
Counter B: 4
Exiting Counter B
Exiting Counter A
When creating threads, there are a few reasons why implementing the Runnable interface may be preferable to extending the Thread class:
- Extending the Thread class means that the subclass cannot extend any other class, whereas a class implementing the Runnable interface has this option.
- Extending the Thread class also means that the task of the thread—that is, executing the run() method—cannot be shared by several threads. This does not mean that the threads cannot access shared resources through their run() methods—which is typical in multithreaded applications.
- A class might only be interested in being runnable, and therefore, inheriting the full overhead of the Thread class would be excessive.