Concepts / Creating and Starting Threads in Java

Creating and Starting Threads in Java

A thread is alive from the time it is started until it terminates, and a dead thread cannot be restarted; isAlive() tests whether a thread has terminated.

  • Programming

A Background Download and the Main Thread

Imagine a program in which a background thread downloads a file while the main thread keeps the user interface responsive. At some point the main thread needs to know whether the download is finished. It cannot simply assume the answer, and it cannot reach into the other thread and read its progress directly. Java provides a small set of methods on the Thread class that let one thread observe, pause, and signal another.

This article follows those methods through one question at a time: how to ask whether a thread is still going, how to pause a thread, how to send it a signal, and how the receiving thread notices that signal. Along the way, you will trace a single thread through its states, because the rules for these methods depend on which state the thread is in.

Following a Thread from Start to Death

Definition

A thread is alive from the time it is started until it terminates. Once it terminates, it is called dead. A dead thread cannot be restarted.

A thread becomes alive at the moment it is started, and it stays alive until it terminates. Terminating happens when the run() method ends for some reason. The same idea is sometimes described as killing or aborting a thread. Whichever word you use, the important point is the same: a thread that has terminated cannot be restarted.

Being alive does not mean the thread is always running on the processor. A thread that has been started may be running, or it may be sleeping. A sleeping thread is still alive but not running. Sleeping is one of the pauses the Thread class offers, and it is covered later in this article.

What do you think happens?

A thread has been started and is currently sleeping inside sleep(). Is it alive, or is it dead?

  • Alive, because it has been started and has not terminated

  • Dead, because it is not running

Reveal answer
Answer:

Alive, because it has been started and has not terminated

A sleeping thread is still alive but not running. Dead only applies after the thread has terminated, which happens when its run() method ends.

Not yet startedAlive and runningDeadAlive and sleepingstart()sleep()wakes uprun() ends
At which points does a thread move from not-yet-alive to alive to dead, and what triggers each transition?

The diagram traces the transitions. Calling start() moves the thread from not yet started into the alive state. Calling sleep() moves it into alive-but-sleeping. A sleeping thread can wake, either after its pause or early when an interrupt arrives. When the run() method finally ends, the thread becomes dead, and no further start() can bring it back.

Checking Whether a Thread Has Finished

Sometimes one thread needs to know whether another has finished. For this purpose a Thread object provides the method isAlive(). If thrd is a Thread, then thrd.isAlive() is a boolean-valued method that tests whether thrd has terminated. It answers a yes-or-no question about the thread it is called on, which makes it a natural tool for a waiting or monitoring thread.

Code walkthrough
public class AliveDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread worker = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // worker was not interrupted in this example
            }
        });
        worker.start();
        System.out.println(worker.isAlive());
        Thread.sleep(2000);
        System.out.println(worker.isAlive());
    }
}
  1. 1
    Line 3 creates a Thread object whose run() method sleeps for one second.
  2. 2
    Line 9 starts the worker, which moves it into the alive state.
  3. 3
    Line 10 asks isAlive() and gets true because the worker has not terminated.
  4. 4
    Line 11 pauses the main thread so the worker has time to finish.
  5. 5
    Line 12 asks isAlive() again and gets false because the worker has terminated.
  • The worker thread is started, so it becomes alive.
  • The first isAlive() call happens while the worker is still sleeping, so it reports true.
  • The main thread then waits 2000 milliseconds, longer than the worker's 1000-millisecond pause.
  • By then the worker's run() method has ended and the worker is dead, so isAlive() reports false.
Output
true
false

Why a Dead Thread Stays Dead

A common assumption is that a Thread object can be reused for another run after it finishes. The source is clear that it cannot. A terminated thread is dead, and a dead thread cannot be restarted. If you want the work to happen again, you create a new Thread object and start that one.

SituationDead Thread objectNewly created Thread object
Current stateTerminated, because its run() method has endedNot yet started, so not alive
Can start() bring it back to life?No, a dead thread cannot be restartedYes, start() makes it alive for the first time
What to do to run the work againCreate a new Thread object insteadCall start() on this object
Result of isAlive() right after start()Not applicable, because the thread cannot be restartedReports true while the thread has not yet terminated

Reusing a Thread object is not an option once it is dead. A new Thread object is the way to run the work again.

Pausing a Thread with sleep()

Signalling a Sleeping Thread with interrupt()

Sometimes one thread needs to wake up another thread that is sleeping, or that has paused for some other reason. For this, you call thrd.interrupt() on the Thread object that should be interrupted. The method is a convenient way to send a signal from one thread to another. The receiving thread is not forced to stop. It is simply told that something has happened, and how it responds is up to the code in its catch handler.

Main threadWorker threadsleepingCatch handler1. interrupt()2. InterruptedException3. catch code runs
When main calls interrupt() on a thread that is inside sleep(), what happens to the sleeping thread and where does control go next?

The diagram shows the exchange in order. The main thread sends the signal with interrupt(). The sleeping worker does not learn about it through any special mechanism other than the exception. The InterruptedException is thrown, control moves into the catch handler, and the worker's own code decides what to do next.

Code walkthrough
public class InterruptDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread worker = new Thread(() -> {
            try {
                Thread.sleep(5000);
                System.out.println("Finished sleeping");
            } catch (InterruptedException e) {
                System.out.println("Interrupted while sleeping");
            }
        });
        worker.start();
        Thread.sleep(500);
        worker.interrupt();
    }
}
  1. 1
    Lines 3 to 11 define the worker, whose sleep is wrapped in a try..catch.
  2. 2
    Line 12 starts the worker, which moves it into the alive state and begins its sleep.
  3. 3
    Line 13 pauses the main thread for half a second, so the worker is already sleeping.
  4. 4
    Line 14 calls interrupt() on the worker, which signals it.
  5. 5
    The worker's sleep throws InterruptedException, and control moves into the catch block, which prints a message and ends the run() method.
  • The worker is set to sleep for five seconds.
  • The main thread waits briefly, then calls interrupt() on the worker.
  • The worker's catch block handles the signal rather than being forced to stop.

Checking the Flag with Thread.interrupted()

The catch handler is not the only place a thread can discover an interrupt. Outside any catch handler, a thread can ask whether it has been interrupted by calling the static method Thread.interrupted(). This method tells whether the current thread, meaning the thread that executes the call, has been interrupted. It is a question about the thread that is asking, not about some other thread.

Thread.interrupted() has an unusual property: it clears the interrupted status when it answers. After one call, the status is reset, so a second call reports false unless another interrupt has arrived in between. This is why the check gives you only one chance to see the interruption. If you need the answer more than once, save the result in a variable.

Interrupted statussetFirst call returnstrueSecond call returnsfalseStatus clearedThread.interrupted() calledcall clears itThread.interrupted() called again
After interrupt() sets the status, what value does each successive call to Thread.interrupted() return, and why is there only one chance to see true?
Worked example

Two checks after one interrupt

A thread has been interrupted, so its interrupted status is set. The thread calls Thread.interrupted() twice in a row, with no other interrupt arriving between the calls. What does each call return?

  1. 1
    First call

    The status is set, so the call reports true. Because the call clears the status as it answers, the status is now reset.

  2. 2
    Second call

    The status was cleared by the first call, and no new interrupt has arrived, so this call reports false.

  3. 3
    Saving the result

    If the code needed the true answer later, it should have stored the first result in a variable rather than calling Thread.interrupted() a second time.

Result

The first call returns true and the second returns false. Only the first call sees the interruption.

Mistakes Beginners Make with Thread States

  • Common mistake

    Trying to restart a thread by calling start() on the same dead Thread object

    Why it fails

    A thread that has terminated cannot be restarted.

    Do this instead

    Create a new Thread object and start that one to run the work again.

  • Common mistake

    Treating isAlive() true as proof that the thread is currently running

    Why it fails

    A sleeping thread is still alive but not running, so the answer does not describe what the processor is doing.

    Do this instead

    Read isAlive() as only telling you whether the thread has terminated yet.

  • Common mistake

    Calling interrupt() and expecting the thread to stop immediately

    Why it fails

    The receiving thread is not forced to stop. It is simply told that something has happened.

    Do this instead

    Write the catch handler, or the interrupted check, so the thread decides how to respond.

  • Common mistake

    Calling Thread.interrupted() twice and expecting true both times

    Why it fails

    The call clears the interrupted status when it answers, so the second call reports false unless another interrupt arrived.

    Do this instead

    Store the first result in a variable and test that variable as many times as needed.

  • Common mistake

    Wrapping sleep() in an empty catch block and losing the signal entirely

Practice: Predict the Thread States

MEDIUM

A worker thread is started and then calls sleep(3000). One second later, the main thread calls interrupt() on the worker. Describe the worker's state before the interrupt, what happens at the moment of the interrupt, and whether the worker can be restarted afterward once its run() method has ended.

Hints
  • Before the interrupt, the worker is alive but sleeping.
  • The interrupt arrives as an InterruptedException inside the worker's sleep call.
  • Once run() ends, the worker is dead, and a dead thread cannot be restarted.

Key Takeaways

  • A thread is alive from the moment it is started until it terminates, and a dead thread cannot be restarted. A sleeping thread is still alive but not running.
  • isAlive() tests whether a thread has terminated, so it answers a yes-or-no question about one moment in time.
  • Thread.sleep(milliseconds) pauses the calling thread, and its InterruptedException is checked, so it must be handled, usually with try..catch.
  • interrupt() sends a signal to a sleeping or paused thread. The receiving thread learns of it through an InterruptedException or by calling Thread.interrupted(), and it decides how to respond.
  • Thread.interrupted() checks the status of the current thread and clears it as it answers, so save the result if you need it more than once.