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:
- NEW (initialization status)
- RUNNABLE (RUNNABLE / running state)
- BLOCKED
- WAITING (unlimited WAITING state)
- TIMED_WAITING (time limited waiting state)
- 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