Interview Raider 23: talk about the thread life cycle and the conversion process?

The life cycle of a thread refers to the whole process from creation to destruction. Generally, there are five kinds of thread life cycles:

  • Initial state
  • Operational status
  • running state
  • Dormant state
  • Termination status

Their state transitions are shown in the following figure:

Java thread lifecycle

The life cycle of Java thread is different from that mentioned above. It has the following six states:

  1. NEW (initialization status)
  2. RUNNABLE (RUNNABLE / running state)
  3. BLOCKED
  4. WAITING (unlimited WAITING state)
  5. TIMED_WAITING (time limited waiting state)
  6. TERMINATED

We can find these six states in the source code of Thread, as shown below:

Of course, you can also use Java code to print all thread states, as shown in the following code:

for (Thread.State value : Thread.State.values()) {
    System.out.println(value);
}

The execution results of the above procedures are shown in the figure below:

Life cycle transformation

Let's talk about the Java thread life cycle.

1. From NEW to RUNNABLE

When we create a thread, that is, new Thread, the thread is in NEW state, as shown in the following code:

// Create thread
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        // ...
    }
});
// Get thread status
Thread.State state = thread.getState();
System.out.println(state);

The execution results of the above procedures are shown in the figure below:

However, after calling the start method of the thread, the state of the thread changes from NEW to RUNNABLE, as shown in the following code:

// Create thread
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        // Gets the thread currently executing
        Thread currThread = Thread.currentThread();
        // Get thread status
        Thread.State state = currThread.getState();
        // Print thread status
        System.out.println(state);
    }
});
thread.start();

The execution results of the above procedures are shown in the figure below:

2. From RUNNABLE to BLOCKED

When the code in the thread is queued to execute synchronized, the thread will change from RUNNABLE state to BLOCKED state, as shown in the following code:

// Create thread
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            // Wait 100 milliseconds
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Queue lock");
        synchronized (ThreadStates.class) {
        }
    }
});
thread.start();
// Let the main thread get the lock first
synchronized (ThreadStates.class) {
    // Get thread status
    Thread.State state = thread.getState();
    // Print thread status
    System.out.println("Get thread status for the first time:" + state);
    // Sleep for 1s
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    // Get thread status again
    state = thread.getState();
    // Print thread status
    System.out.println("Get thread status for the second time:" + state);
}

The execution results of the above procedures are shown in the figure below:

When the thread obtains the synchronized lock, it will change from the BLOCKED state to the RUNNABLE state.

3. From RUNNABLE to waiting

After the thread calls the wait() method, it will change from the RUNNABLE state to the WAITING unlimited wait state, as shown below:

// Create thread
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        synchronized (this) {
            try {
                // Thread sleep
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
});
// Start thread
thread.start();
// Get thread status
Thread.State state = thread.getState();
// Print thread status
System.out.println("Get thread status for the first time:" + state);
// Sleep for 1s
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
// Get thread status
state = thread.getState();
// Print thread status
System.out.println("Get thread status for the second time:" + state);

The execution results of the above procedures are shown in the figure below:

When the notify/notifyAll method is called, the thread will change from WAITING state to RUNNABLE state, as shown in the following code:

Object lock = new Object();
// Create thread
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        synchronized (lock) {
            try {
                // Thread sleep
                lock.wait();
                // Get current thread status
                Thread.State state = Thread.currentThread().getState();
                // Print thread status
                System.out.println("Get thread status:" + state);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
});
// Start thread
thread.start();
// Get thread status
Thread.State state = thread.getState();
// Print thread status
System.out.println("Get thread status for the first time:" + state);
// Sleep for 1s
try {
    Thread.sleep(100);
} catch (InterruptedException e) {
    e.printStackTrace();
}
// Get thread status
state = thread.getState();
// Print thread status
System.out.println("Get thread status for the second time:" + state);

// Wake up thread
synchronized (lock) {
    lock.notify();
}

The execution results of the above procedures are shown in the figure below:

4. From RUNNABLE to TIMED_WATTING

When calling the wait method with timeout, such as sleep(xxx), the thread will change from the RUNNABLE state to TIMED_WAITING has time limit status, as shown in the following code:

// Create thread
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});
// Start thread
thread.start();
// Get thread status
Thread.State state = thread.getState();
// Print thread status
System.out.println("Get thread status for the first time:" + state);
// Sleep for 1s
try {
    Thread.sleep(100);
} catch (InterruptedException e) {
    e.printStackTrace();
}
// Get thread status
state = thread.getState();
// Print thread status
System.out.println("Get thread status for the second time:" + state);

The execution results of the above procedures are shown in the figure below:

When the timeout period is exceeded, the thread will start from timed_ The waiting state changes to the RUNNABLE state, and the implementation code is as follows:

// Create thread
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
            // Get current thread status
            Thread.State state = Thread.currentThread().getState();
            // Print thread status
            System.out.println("Get thread status:" + state);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});
// Start thread
thread.start();
// Get thread status
Thread.State state = thread.getState();
// Print thread status
System.out.println("Get thread status for the first time:" + state);
// Sleep for 1s
try {
    Thread.sleep(100);
} catch (InterruptedException e) {
    e.printStackTrace();
}
// Get thread status
state = thread.getState();
// Print thread status
System.out.println("Get thread status for the second time:" + state);

The execution results of the above procedures are shown in the figure below:

5.RUNNABLE to TERMINATED

After the thread is executed, it will change from the RUNNABLE state to the TERMINATED destruction state, as shown in the following code:

// Create thread
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        // Get current thread status
        Thread.State state = Thread.currentThread().getState();
        // Print thread status
        System.out.println("Get thread status:" + state);
    }
});
// Start thread
thread.start();
// Wait for 100ms until the thread is finished
Thread.sleep(100);
// Get thread status
Thread.State state = thread.getState();
// Print thread status
System.out.println("Thread status:" + state);

The execution results of the above procedures are shown in the figure below:

summary

There are six kinds of thread life cycles in Java: NEW, RUNNABLE, BLOCKED, WAITING and TIMED_WAITING, TERMINATED. The conversion process of thread life cycle is shown in the following figure:

reference material

Java Concurrent Programming Practice
‚Äč

Right and wrong are judged by ourselves, bad reputation is heard by others, and the number of gains and losses is safe.

The official account: Java interview

Interview collection: https://gitee.com/mydb/interview

Keywords: Java

Added by dagon on Fri, 18 Feb 2022 08:46:43 +0200