This is the seventh day of my participation in the More text Challenge. For details, see more text Challenge

To learn about thread state and transitions in Java, we can first look at thread state transitions in an operating system.

Thread state transition in the operating system

Threads in an operating system are considered lightweight processes, so the thread state of the operating system is consistent with the process state.

The four states are active ready, stationary ready, active blocking, and stationary blocking, which are described as follows:

Active ready (Readya) : equivalent to the ready state. At this time, the process can accept scheduling and can be directly converted to the execution state after obtaining the processor; Readys: The process has been transferred to external storage and cannot be scheduled. Blockeda: Equivalent to the blocked state, which can be changed from the active blocked state to the active ready state when a waiting event occurs; Blockeds: A process can still wait for an event, and when the event occurs, its state changes from static blocked to static ready.

6 states of Java threads

  • Initial (NEW) : A NEW thread object has been created, but the start() method has not yet been called.
  • RUNNABLE: Java threads generally refer to both ready and running states as “running.”
  • BLOCKED: Indicates that a thread is BLOCKED from a lock.
  • WAITING: The thread in this state is WAITING for some specific action (notification or interruption) from another thread.
  • Timeout wait (TIMED_WAITING) : This state, unlike WAITING, can return after a specified time.
  • TERMINATED: indicates that the thread has finished executing.

Several states are described in detail below

1.NEW

When a thread is created, it is in its initial new state before it is started.

private void testStateNew(a) {
    Thread thread = new Thread(() -> {});
    System.out.println(thread.getState()); / / output is NEW
}
Copy the code

2.RUNNABLE

Indicates that the thread is running. You may be running in a Java virtual machine, or you may be waiting for CPU resources to be allocated. The two states, ready and running, are generally called “running.”

3.BLOCKED

Blocked state. A thread in the BLOCKED state is waiting for the lock to be released to enter the synchronization area.

4 WAITING

Wait state. Threads in the wait state need to be woken up by other threads to become RUNNABLE.

Calling the following three methods puts the thread into a wait state:

  • Object.wait() : causes the current thread to wait until another thread wakes it up;
  • Thread.join() : wait for the Thread to finish executing.
  • Locksupport.park () : Disables the current thread for thread scheduling unless authorized to call.

5.TIMED_WAITING

Timeout waiting status. The thread waits for a specific time and is automatically awakened when the time is up.

Calling the following method causes the thread to enter a timeout wait state:

  • Thread.sleep(long millis) : make the current Thread sleep for a specified time;
  • Object.wait(Long Timeout) : The specified time for a thread to sleep, which can be awakened by notifyAll() /notifyAll();
  • Thread.join(long millis) : wait for the current Thread to execute millis for a maximum of milliseconds. If millis is 0, the Thread will execute all the time.
  • Locksupport.parknanos (long Nanos) : Disables the current thread for a specified time of thread scheduling unless authorized to do so;
  • Locksupport. parkUntil(long Deadline) : same as above, which also disallows threads from scheduling a specified time;

6.TERMINATED

Termination status. At this point, the thread has finished executing.

3. Transition of thread state

1. The transition between BLOCKED and RUNNABLE states

We said above that a thread in the BLOCKED state is waiting for the lock to be released. If there are two threads, A and B, BLOCKED from work, thread A acquired the lock early and has not released it. Let’s start with an example:

@Test
public void blockedTest() {

    Thread a = new Thread(new Runnable() {
        @Override
        public void run(){ testMethod(); }},"a");
    Thread b = new Thread(new Runnable() {
        @Override
        public void run(){ testMethod(); }},"b");

    a.start();
    b.start();
    System.out.println(a.getName() + ":" + a.getState()); / / output?
    System.out.println(b.getName() + ":" + b.getState()); / / output?
}

// Synchronous methods compete for locks
private synchronized void testMethod() {
    try {
        Thread.sleep(2000L);
    } catch(InterruptedException e) { e.printStackTrace(); }}Copy the code

At first glance, you might think that Thread A calls the synchronized method first, and within that method thread.sleep () calls TIMED_WAITING, and Thread B prints BLOCKED as it waits for Thread A to release the lock.

There is also a main thread inside the blockedTest() method, and it takes some time to execute the run method once the thread is started.

The main thread of the test method only guarantees that a and B will call start(). If the CPU is more efficient, it will print the RUNNABLE state of the two threads before they actually start to fight for the lock.

Of course, if the CPU executes less efficiently, it is possible for one of these threads to print the BLOCKED state (at which point the two threads are already competing for the lock).

At this point, you might ask, what should I do if I want to print the BLOCKED state? The BLOCKED state requires two threads to compete for the lock. Let’s handle the main Thread in the test method, give it a “rest” and call thread.sleep ().

The important thing to note here is how long the main thread is at rest. Make sure that the lock is not contested until the previous lock is released, and you are still not in the BLOCKED state.

Let’s change blockedTest() :

public voidBlockedTest () throws InterruptedException {···· a.start(); Thread.sleep(1000L);// Note that the main thread is hibernated for 1000 milliseconds, while testMethod() is hibernated for 2000 milliseconds
    b.start();
    System.out.println(a.getName() + ":" + a.getState()); / / output?
    System.out.println(b.getName() + ":" + b.getState()); / / output?
}
Copy the code

The state transition between the two threads in this example is as follows

  • RUNNABLE (a.start()) -> TIMED_WATING (thread.sleep ()) ->RUNABLE (sleep() time up) -> TERMINATED (failed to snatch the lock) -> TERMINATED
  • RUNNABLE (B.start ()) ->TERMINATED ->TERMINATED

The italics are the possible states, so you can try it a few times on your computer and look at the output. Again, the output here may have multiple results.

2. The transition between WAITING state and RUNNABLE state

From the transition diagram we know that there are three ways to get a thread from the RUNNABLE state to the WAITING state. We mainly introduce object.wait () and thread.join ().

Object.wait()

The thread must hold the lock on the object before the wait() method can be called.

When a thread calls wait(), it releases the current lock until another thread calls notify()/notifyAll() to wake up the thread waiting for the lock.

Note that a call to notify() from another thread will only wake up a single thread waiting for the lock. If more than one thread is waiting for the lock, it will not necessarily wake up the thread that previously called wait().

Similarly, a call to notifyAll() that wakes up all the threads waiting for a lock may not immediately allocate the time slice to the thread that gave up the lock, depending on system scheduling.

Thread.join()

Calling the join() method does not release the lock and will wait until the current thread finishes executing (transitions to the TERMINATED state).

Let’s change where the above example thread starts again:

public void blockedTest(){· · · · · · a.s tart (); a.join(); b.start(); System.out.println(a.getName() +":" + a.getState()); / / output is TERMINATED
    System.out.println(b.getName() + ":" + b.getState());
}
Copy the code

If the join method is not called, the main thread will continue regardless of whether the A thread finishes executing.

The join method is called as soon as the thread is started. The main thread will wait until the thread finishes executing, so the state of the print is fixed.

As for the state of thread B, it is possible to print RUNNABLE (not yet in the synchronized method) or TIMED_WAITING (in the synchronized method).

3.TIMED_WAITING and RUNNABLE state transition

TIMED_WAITING is similar to the WAITING state except that the WAITING time for the TIMED_WAITING state is specified.

Thread.sleep(long)

Causes the current thread to sleep for a specified time. Note that the “sleep” here only temporarily stops the thread from executing, and does not release the lock. When the time is up, the thread will return to the RUNNABLE state.

Object.wait(long)

The wait(long) method puts the thread into the TIMED_WAITING state. The wait(long) method here has the same effect as the unparameterized wait() method in that it can be awakened by another thread calling the notify() or notifyAll() method.

The difference is that the wait(long) method will automatically wake it up after the specified long, even if other threads do not wake it up.

Thread.join(long)

Join (long) causes the current thread to execute the specified time, and causes the thread to enter TIMED_WAITING state.

Let’s change the example again:

public void blockedTest(){· · · · · · a.s tart (); a.join(1000L); b.start(); System.out.println(a.getName() +":" + a.getState()); / / output TIEMD_WAITING
    System.out.println(b.getName() + ":" + b.getState());
}
Copy the code

Here, we call a.join(1000L), because the execution time of a thread is specified, and the execution time is less than the time of a thread sleep, so the state of a thread output TIMED_WAITING.

B The thread state is still not fixed (RUNNABLE or BLOCKED).

4. The thread is interrupted

In some cases, we need to interrupt a thread after it has started when it is not needed to continue. There is currently no safe, direct way to stop a thread in Java, but Java provides a thread interrupt mechanism to handle situations where it is necessary to interrupt a thread.

The thread interrupt mechanism is a cooperative mechanism. Note that interrupts do not terminate a thread directly, but instead tell the thread to handle it itself.

The Thread class provides several methods for Thread interrupts:

  • Thread.interrupt() : Interrupts the Thread. The interrupt thread here does not stop the thread immediately, but sets the interrupt status of the thread to true (default is flase);
  • Thread.interrupted() : Tests whether the current Thread has been interrupted. The interrupt status of a thread is affected by this method, meaning that a single call will set the thread’s interrupt status to true, and two consecutive calls will change the thread’s interrupt status to false again.
  • Thread.isinterrupted () : tests whether the current Thread isInterrupted. Unlike the above method, calling this method does not affect the interrupt state of the thread.

In thread interrupts, the status of a thread is set to true when the thread is notified by another thread, but it is entirely up to the thread itself to handle the interrupts. It can actually handle the interrupt request when it is appropriate, or it can continue executing without processing it at all.