Creating and Running Threads
A thread can be defined by creating a subclass of Thread and overriding the run() method.
A Thread Is a Unit of Work
A thread is a unit of work that can run alongside other work in the same program. Before you can use threads in a useful way, you need to know how to tell Java what a particular thread should do. That is the single idea this article is about: how a subclass of Thread carries the definition of a thread's task. The source describes two ways to program a thread. This article covers only the subclass route.
Read the code in the next section first, then test your understanding with the prediction question before the explanation arrives. The approach is deliberate: most of what matters about threads is about the order of events, and the example is built to make that order visible.
Reading the NamedThread Class
The source uses a class whose only job is to print a greeting. The source describes this example as rather useless on its own. Its value is that it isolates one idea: how a subclass of Thread holds the definition of a thread's task. The class below is an illustrative version written for this article in that same style. It contains two parts with distinct jobs.
public class NamedThread extends Thread {
private String name;
public NamedThread(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println("Hello from " + name);
}
}- 1The phrase extends Thread makes
NamedThreada subclass of Thread, which is the subclass route for programming a thread. - 2The constructor takes a name and stores it in the private field name, so each object remembers its own name.
- 3The
run()method is the part that matters for the thread's behavior, because it is the method that defines the task the thread will perform.
- extends Thread makes
NamedThreada subclass of Thread - The constructor takes a name and stores it in the private field
run()defines the task the thread will perform
Tracing Construction Versus Start
Creating an object of the thread subclass does not by itself run the task. The constructor typically sets up data such as a name. The task runs only when the thread is started. When you trace a thread program, keep two steps apart: the construction step, and the step where the thread starts and run() executes. The main program below creates a NamedThread and then starts it.
Hello from Ada- Line 3 constructs the object and stores the name Ada; no greeting is printed yet
- Line 4 starts the thread, which causes
run()to execute and print the greeting
Read the diagram as two separate phases. The first arrow is construction, which sets up the name. The second arrow happens only when the thread is started, and that is the point where run() executes. The arrow back to the main program stands for the output appearing. The source does not describe any return value from run(), so the diagram does not show one.
What do you think happens?
If the line t.start() is removed and only new NamedThread("Ada") runs, what gets printed?
Reveal answer
Nothing is printed
Constructing the object sets up the name, but the source states that creating an object does not by itself run the task. The run() method executes when the thread is started, so without start() the greeting never appears.
Where run() Defines the Task
The run() method is the place where a thread's task is defined. When a class extends Thread and overrides run(), the code inside run() becomes the work the thread performs. The source states that run() defines the task performed by the thread and that it executes when the thread is started. The class itself is a subclass of Thread, so it inherits the thread behavior and supplies its own task by overriding run().
Following the Lifecycle of a Thread Object
A thread object can exist in a constructed state before it has been started. In that state the object holds its data, such as the name, but its task has not begun. Starting the thread is the event that moves it to the state where run() executes. The source does not name further states, so this diagram shows only the two states the source describes.
Where a Thread's Output Comes From
The output of a thread's work comes from the code inside its run() method. In the NamedThread example, the greeting is printed because run() contains the print statement and that statement executes when the thread starts. The output does not come from the constructor, which only stores the name. So if you want to know where a thread's output originates, look inside run().
The source gives no return value from run(), and this article does not claim that run() passes anything back to the main program. The output that appears is produced by the work done inside run() while it executes.
Mistakes When Writing a Thread Subclass
Common mistake Expecting the task to run as soon as the object is constructed
What it looks likeWriting new NamedThread("Ada"); alone and expecting a greeting
Why it failsThe source states that creating an object of the thread subclass does not by itself run the task.
Do this insteadCall start() on the object to make run() execute.
Common mistake Putting the thread's task in the constructor
Why it failsThe source says the constructor typically sets up data such as a name, while
run()defines the task.Do this insteadKeep setup data in the constructor and place the work inside an overridden run() method.
Common mistake Assuming run() returns a value to the main program
Why it failsThe source does not describe any return value from
run(), so this cannot be relied on.Do this insteadExpect the visible result of the work to come from what run() does, such as printing, rather than from a returned value.
Tracing a Thread Program Yourself
Suppose the main method creates two NamedThread objects, one with the name Ada and one with the name Grace, and then calls start() on only the Grace object. Which greeting is printed, and at which step does the first object's name get stored? Explain your answer by separating the construction steps from the start step.
Hints
- Separate the construction step from the step where the thread starts and
run()executes. - Only objects whose
start()method is called have theirrun()method executed.
Key Takeaways on Thread Creation
- 1A thread can be defined by creating a subclass of Thread and overriding the
run()method. - 2The
run()method defines the task the thread performs and executes when the thread is started. - 3Constructing the thread subclass sets up data such as a name but does not by itself run the task.
- 4The output of a thread's work comes from the code inside
run()while it executes.
At a glance
- A thread can be defined by creating a subclass of Thread and overriding the
run()method. - The
run()method defines the task the thread performs and executes when the thread is started. - Constructing the thread subclass sets up data such as a name but does not by itself run the task.
- The output of a thread's work comes from the code inside
run()while it executes.