Chapter 2 Thread Status

Six states of Java threads

In our operating system, threads correspond to five major states, initial state, ready state, running state, blocking state, and termination state.

img

  • NEW (new state) A new thread object has been created, but the start() method has not been called yet.

  • RUNNABLE (Running state) In Java threads, the two states of READY and RUNNING are collectively called the running state. 其一个线程被创建了,并且调用了这个线程对象的start()方法,这个线程对象就处于可运行的线程池中Waiting to be selected by the scheduler and obtain the right to use the CPU. This state is called the ready state (everything is ready). Ready (only short of CPU), when this thread obtains the right to use the CPU, it will change from ready to running.

  • BLOCKED means that this thread is blocked in the lock

  • Waiting (WAITING) A thread entering this state needs to wait for other threads to take some specific actions (notification or interrupt)

  • Timeout waiting (TIME_WAITING) This state is different from WAITINGM. It returns automatically after the specified time.

  • TERMINATED indicates that the thread has completed execution

BLOCKED, WAITING, TIMED_WAITING are all subdivisions of [blocking state] at the Java API level

The RUNNABLE state at the Java API level covers [runnable state], [running state] and [blocked state] at the operating system level (thread blocking due to BIO cannot be distinguished in Java and is still considered runnable)

img

New status

public class ThreadDemo3 {
    
    
    public static void main(String[] args) {
    
    
        Thread thread = new Thread(() -> {
    
    
            System.out.println("测试线程的状态");
        }, "t1");
        System.out.println(thread.getState());
    }
}
//NEW
  • Regarding NEW, we can get a thread class by implementing the Runnable interface or inheriting Thread. New creates a thread object, and the thread is in the NEW state.

Running state

Ready in running state

  • Ready (READY) only means that you are qualified to run. Only when the system schedules you to run can you be truly RUNNING. Otherwise, you will always be READR, and the real call still requires the intervention of the operating system.
  • A thread in the NEW state calls start() to enter the ready state
  • When the sleep() method of one thread ends, the join of other threads ends, a thread obtains the object lock, and these threads enter the ready state.
  • The current thread's time slice runs out, or the yield() method of the currently running thread is called, and the current thread enters the ready state.
  • After the thread in the lock pool obtains the object lock, it enters the ready state

Running state: Running

  • The thread scheduler selects a thread from the runnable pool (RUNNING and READY) as the running thread. This is the only way for a thread to become running.
public class ThreadDemo3 {
    
    
    static int r = 0;
    public static void main(String[] args) throws InterruptedException {
    
    
        new Thread(()->{
    
    
            System.out.println(Thread.currentThread().getState());
        },"t1").start();
    }
 }
 RUNNABLE

yield enters ready state

  • Calling yield will cause the current thread to enter the Runnable ready state from Running , and then schedule other threads to execute.
  • The specific implementation depends on the task scheduler of the operating system.
public class ThreadDemo3 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Thread thread = new Thread(() -> {
    
    
            int count=1;
            while (true){
    
    
                System.out.println(Thread.currentThread().getName()+"第"+ count++ +"运行");
            }
        }, "t1");
        Thread thread1 = new Thread(() -> {
    
    
            int count=1;
            while (true){
    
    
                System.out.println(Thread.currentThread().getName()+"第"+ count++ +"运行");
                // t2线程就会让出CPU,进入就绪态,等待被CPU继续调度
                Thread.yield();
            }
        }, "t2");
        thread.start();
        thread1.start();
    }
}
t2第283349运行
t2第283350运行
t2第283351运行
t2第283352运行
t2第283353运行
t2第283354运行
t2第283355运行
t1第1052474运行
t1第1052475运行
t1第1052476运行
t1第1052477运行
  • We find that both t1 and t2 threads are running

  • We found that the t2 thread executes yield and gives up the right to use the CPU. The t2 thread just gives up the CPU, but what thread is scheduled next is still decided by our operating system. The t2 thread may be called next time (it is just After we execute the output statement, we give up the CPU), or it may be the t1 thread. We cannot interfere, but every time the t2 thread is executed, the CPU will be given up, so that the t1 thread may execute more times.

What does the yield method in the Thread class do?

  • Change the current thread from execution state (running state) to executable state (ready state).
  • The current thread has reached the ready state, so which thread will change from the ready state to the execution state next? It may be the current thread, or it may be another thread, depending on the system's allocation.

blocking state

synchronized enters the blocking state

public class ThreadDemo3 {
    
    
    static int r = 0;
    public static void main(String[] args) throws InterruptedException {
    
    
        Object o = new Object();
        Thread t1 = new Thread(() -> {
    
    
            synchronized (o) {
    
    
                System.out.println("t1线程进行加锁操作");
                try {
    
    
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        }, "t1");
        Thread t2 = new Thread(() -> {
    
    
            synchronized (o) {
    
    
                System.out.println("t2线程进行加锁操作");
            }
        }, "t2");
        t1.start();
        t2.start();
        TimeUnit.SECONDS.sleep(1);
        System.out.println("t2线程状态为" + t2.getState());
    }
}
t1线程进行加锁操作
t2线程状态为BLOCKED
t2线程进行加锁操作
  • When our t2 thread wants to fight for o resource, but the o resource is occupied by the t1 thread, so the t2 thread enters the blocking state.
  • The relevant knowledge about synchronized and locks will be explained in detail later.

waiting state

  • Threads in this state will not be allocated CPU execution time. They must wait to be explicitly awakened, otherwise they will be in an indefinite waiting state.

join() enters the waiting state

Why do we need to join

public class ThreadDemo3 {
    
    
    static int r = 0;
    public static void main(String[] args) throws InterruptedException {
    
    
        System.out.println(Thread.currentThread().getName()+"开始");
        Thread thread = new Thread(() -> {
    
    
            System.out.println(Thread.currentThread().getName() + "开始");
            try {
    
    
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            r = 10;
            System.out.println(Thread.currentThread().getName() + "结束");
        }, "t1");
        thread.start();
        //thread.join();
        System.out.println("r结果是"+r);
        System.out.println(Thread.currentThread().getName()+"结束");
    }
}
main开始
r结果是0
main结束
t1开始
t1结束
  • Because the main thread and thread t1 are executed in parallel, it takes 1 second for the t1 thread to calculate r=10
  • And the main thread will print the result of r at the beginning, so it can only print r=0, but we just want the result of the t1 thread operation, how to solve it
  • Sometimes, we need to wait for a thread to complete its work before proceeding to the next step. For example, Zhang San only decides whether to save money after waiting for Li Si to transfer money successfully. At this time, we need a method to explicitly wait for the end of the thread.

Solution

  • Is it okay to use sleep? Why?
    • We can let the main thread sleep for 2 seconds, but in many cases, we don't know how long the corresponding thread will take
  • Use join and add it after t1.start()
main开始
t1开始
t1结束
r结果是10
main结束
public class ThreadDemo3 {
    
    
    static int r = 0;
    public static void main(String[] args) throws InterruptedException {
    
    
        Thread thread = new Thread(() -> {
    
    
            try {
    
    
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        });
        Thread thread1 = new Thread(() -> {
    
    
            try {
    
    
                thread.join();
                System.out.println("测试线程状态");
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        });
        thread.start();
        thread1.start();
        TimeUnit.SECONDS.sleep(1);
        System.out.println(thread1.getState());
    }
}
WAITING
测试线程状态
  • join() is just waiting, crazy attribute
  • thread1 must finish thread execution before continuing to execute, call thread.join(), thread enters waiting state

wait() enters the waiting state

public class ThreadDemo3 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Object o = new Object();
        Thread thread = new Thread(() -> {
    
    
            synchronized (o) {
    
    
                try {
    
    
                    System.out.println("t1线程进行等待");
                    o.wait();
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        }, "t1");
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
    
    
            synchronized (o){
    
    
                System.out.println(thread.getName() + "现在是" + thread.getState());
                o.notify();
            }
        },"t2").start();
    }
}
t1线程进行等待
t1现在是WAITING
  • synchronized performs a locking operation, which also occupies the resource of Object. The lock will be explained in detail later.
  • wait enters the waiting state notify to wake up
  • The thread waiting wake-up system will be explained in detail later.

LockSupport.park() enters the waiting state

public class ThreadDemo3 {
    
    
    static int r = 0;
    public static void main(String[] args) throws InterruptedException {
    
    
        Thread thread = new Thread(() -> {
    
    
            LockSupport.park();
        }, "t1");
        thread.start();
        TimeUnit.MILLISECONDS.sleep(200);
        System.out.println(thread.getState());
        LockSupport.unpark(thread);
        TimeUnit.MILLISECONDS.sleep(200);
        System.out.println(thread.getState());
    }
}
WAITING
TERMINATED
  • Park makes the thread enter the waiting state, and unpark(thread) wakes the thread up

  • The thread waiting wake-up system will be explained in detail later.

  • When the current thread calls LockSupport.parkNanos(long nanos) or LockSupport.parkUntil(long millis), the current thread changes from RUNNABLE --> TIMED_WAITING

  • Calling LockSupport.unpark (target thread) or calling the thread's interrupt(), or waiting for a timeout, will cause the target thread to change from TIMED_WAITING–> RUNNABLE

Timeout waiting state

  • Threads in this state will not be allocated CPU execution time, but they do not need to wait indefinitely to be explicitly awakened by other threads. They will automatically wake up after a certain time.

sleep(long) enters the timeout waiting state

  • Calling sleep will cause the current thread to enter the Timed Waiting state (blocked) from Running
  • Other threads can use the interrupt method to interrupt the sleeping thread, then the sleep method will throw InterruptedException
    • About thread interruption, explained in detail later
  • The thread after sleeping may not be executed immediately
  • It is recommended to use TimeUnit's sleep instead of Thread's sleep to obtain better readability.
public class ThreadDemo3 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Thread thread = new Thread(() -> {
    
    
            try {
    
    
                System.out.println("测试线程的状态");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }, "t1");
        System.out.println(thread.getState());
        thread.start();
        System.out.println(thread.getState());
        Thread.sleep(1000);
        System.out.println(thread.getState());
    }
}
NEW
RUNNABLE
测试线程的状态
TIMED_WAITING
  • When the thread calls sleep, the thread enters Timed Waiting

Limiting the use of the CPU - sleep implementation
When the CPU is not used for calculations, do not let while(true) idle and waste the CPU. At this time, you can use yield or sleep to give up the use of the CPU to other programs.

while(true) {
    
    
	try {
    
    
		Thread.sleep(50);
	} catch (InterruptedException e) {
    
    
		e.printStackTrace();
	}
}
  • You can use wait or condition variables to achieve similar effects
  • The difference is that the latter two require locking and corresponding wake-up operations, which are generally suitable for scenarios where synchronization is required.
  • sleep is suitable for scenarios where lock synchronization is not required

join(long) enters the timeout waiting state

public class ThreadDemo3 {
    
    
    static int r = 0;
    public static void main(String[] args) throws InterruptedException {
    
    
        Thread thread = new Thread(() -> {
    
    
            try {
    
    
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        });
        Thread thread1 = new Thread(() -> {
    
    
            try {
    
    
                thread.join(1000);
                System.out.println("测试线程状态");
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        });
        thread.start();
        thread1.start();
        TimeUnit.MILLISECONDS.sleep(500);
        System.out.println(thread1.getState());
    }
}
TIMED_WAITING
测试线程状态
  • Printing TIMED_WAITING indicates that in order to wait for thread1, thread2 called join(long) and entered the timeout waiting state.
  • join(long time) Wait rationally. How many milliseconds can I wait for you at most? If the execution is completed, it will be fine. If the execution is not completed, I won’t wait for you.

Why are the sleep() and yield() methods of Thread class static?

  • The sleep() and yield() methods of the Thread class will run on the currently executing thread to perform corresponding operations. So it doesn't make sense to call these methods on other threads that are waiting. That's why these methods are static.

If sleep and yield are static methods, then no matter which thread, it will give itself to sleep and yield as soon as it is called.

It would be hilarious if sleep and yield were instance methods. A thread can obtain a reference to another thread's object, and then call the sleep and yield methods of other threads through the reference to let other threads give up CPU usage rights. Just imagine, if each thread could obtain CPU usage rights by sleeping and yielding other threads, the world would be in chaos. Threads can sleep and yield each other.

Come on, let's hurt each other, no one should use the CPU!

What is the difference between the sleep() method and the yield() method of a thread

  • The sleep() method does not consider the priority of the thread when giving other threads a chance to run, so it will give low-priority threads a chance to run; the yield() method will only give threads of the same priority or higher priority a chance to run. Chance;
  • The thread transfers to TIMED_WAITING (timeout waiting) after executing the sleep() method, and transfers to the READY state after executing the yield() method.
  • The sleep() method declares to throw InterruptedException, while the yield() method does not declare any exception;
  • The sleep() method is more portable than the yield() method (related to operating system CPU scheduling). It is generally not recommended to use the yield() method to control the execution of concurrent threads.

wait(long) enters the timeout waiting state

public class ThreadDemo3 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Object o = new Object();
        Thread thread = new Thread(() -> {
    
    
            synchronized (o) {
    
    
                try {
    
    
                    System.out.println("t1线程进行等待");
                    o.wait(1000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        }, "t1");
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
    
    
            synchronized (o){
    
    
                System.out.println(thread.getName() + "现在是" + thread.getState());
                o.notify();
            }
        },"t2").start();
    }
}
t1线程进行等待
t1现在是TERMINATED
  • Wait for a period of time. If the thread is awakened within this time, execution will continue. If no other thread wakes up the thread after the corresponding time, the thread will no longer wait and resume execution.

terminal state

public class ThreadDemo3 {
    
    
    static int r = 0;
    public static void main(String[] args) throws InterruptedException {
    
    
        Thread t1 = new Thread(() -> {
    
    
            System.out.println("t1线程运行完毕");
        }, "t1");
        t1.start();
        TimeUnit.MILLISECONDS.sleep(100);
        System.out.println("t1线程的状态为"+t1.getState());
    }
}
t1线程运行完毕
t1线程的状态为TERMINATED

Thread priority

  • The thread priority will hint to the scheduler that the thread should be scheduled first, but it is only a hint and the scheduler can ignore it.
  • If the CPU is busy, threads with higher priority will get more time slices, but when the CPU is idle, priority has almost no effect.
  • The higher the priority thread, the more likely it is that the CPU will execute it first. We in JAVA only recommend that the thread with the highest priority be executed. Whether it will be executed or not depends on the operating system.
public class ThreadDemo4 {
    
    
    public static void main(String[] args) {
    
    
        Thread thread = new Thread(() -> {
    
    
            System.out.println("测试线程优先级");
        }, "t1");
        //获取线程优先级
        System.out.println(thread.getPriority());
        //设置线程优先级
        thread.setPriority(Thread.MAX_PRIORITY);
        System.out.println(thread.getPriority());
    }
}
5
10

Guess you like

Origin blog.csdn.net/qq_50985215/article/details/131510486