Concepts / Creating and Running Threads

Creating and Running Threads

A thread can be defined by creating a subclass of Thread and overriding the run() method.

  • Programming

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.

Code walkthrough
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);
    }
}
  1. 1
    The phrase extends Thread makes NamedThread a subclass of Thread, which is the subclass route for programming a thread.
  2. 2
    The constructor takes a name and stores it in the private field name, so each object remembers its own name.
  3. 3
    The 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 NamedThread a 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.

java
Output
Hello from Ada
Notes on the code
  • 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
Main programNamedThread objectrun() methodconstruct with name Adastart()executes taskoutput appears
Which step creates the object, and which step causes the run() method to execute?

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?

  • Hello from Ada

  • Nothing is printed

Reveal answer
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.

Constructed, notstartedStarted, run()executingstart()
After new NamedThread("Ada") is created but start() has not been called, what state is the object in, and what happens to run()?

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 like

    Writing new NamedThread("Ada"); alone and expecting a greeting

    Why it fails

    The source states that creating an object of the thread subclass does not by itself run the task.

    Do this instead

    Call start() on the object to make run() execute.

  • Common mistake

    Putting the thread's task in the constructor

    Why it fails

    The source says the constructor typically sets up data such as a name, while run() defines the task.

    Do this instead

    Keep 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 fails

    The source does not describe any return value from run(), so this cannot be relied on.

    Do this instead

    Expect 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

EASY

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 their run() method executed.

Key Takeaways on Thread Creation

  1. 1
    A thread can be defined by creating a subclass of Thread and overriding the run() method.
  2. 2
    The run() method defines the task the thread performs and executes when the thread is started.
  3. 3
    Constructing the thread subclass sets up data such as a name but does not by itself run the task.
  4. 4
    The 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.