The basic principle of thread and Thread Dump thread analysis
-
- Fundamentals of threads
- The running state of the thread
- How to interrupt a thread
-
- There is a looping thread interrupt
- A blocked thread is interrupted
- Thread Dump thread analysis
-
- The CPU is not high, but the response is very slow
- High CPU and slow response
The basic principle of thread
Put a schematic diagram of the thread:
After the java code creates a thread, we start the thread by calling the start()
method, and call the thread.cpp method to start the thread. The bottom layer is still through the create_thread
and of the operating system The thread operated by the >start_thread
method
The running state of the thread
During the running process of a thread, there will be several different states. Generally speaking, in Java, the state of a thread is a total of 6 states, which are
NEW: In the initial state, the thread is constructed, but the start method has not been called yet
**RUNNABLED: **Running state, the JAVA thread refers to the two states of ready and running in the operating system as “running”
**BLOCKED: **Blocked state, indicating that the thread enters the waiting state, that is, the thread gives up the right to use the CPU for some reason, blocking
There are also several situations
- Waiting for blocking: the running thread executes the wait method, and jvm will put the current thread into the waiting queue
- Synchronous blocking: When the running thread acquires the synchronization lock of the object, if the synchronization lock is occupied by other thread locks, then jvm will put the current thread into the lock pool
- Other blocking: When the running thread executes the Thread.sleep or t.join method, or sends out an I/O request, the JVM will set the current thread to a blocked state. When the sleep ends, the join thread terminates, and the io processing is completed, the thread resumes
WAITING: waiting state
TIME_WAITING : Timeout waiting state, automatically return after timeout
TERMINATED: Terminated status, indicating that the current thread has finished executing
How to interrupt a thread
Thread provides some operation methods of threads, such as stop, suspend, etc. These methods can terminate a thread or
Suspend a thread, but these methods are not recommended for everyone to use. Because these methods are methods of forced interruption, half of the execution of the thread task is forced to be interrupted, which may cause data problems. This behavior is similar to executing kill -9
command in linux system, which is an unsafe operation.
Under normal circumstances, threads do not require manual intervention by the user. Which thread interruptions require external intervention?
- There is an infinite loop in the thread
- There are some blocking operations in the thread, such as sleep, wait, join, etc.
Thread interruption with loop
public class ThreadA extends Thread {<!-- --> public void run() {<!-- --> while(true){<!-- --> System.out.println("ThreadA ...."); } } public static void main(String[] args) {<!-- --> ThreadA myThread1 = new ThreadA(); myThread1. start(); } }
For the situation where there is an infinite loop in the thread, there must be an end condition in the code, and the user can modify this end condition elsewhere so that the thread can perceive the change. Like the code above, we change while(true)
to while(flag)
, and then this flag
can be modified externally as a shared variable. After the modification, the loop condition is not satisfied, then exit the loop and end the thread
Java provides a interrupt
method, this method is to realize the thread interruption operation, and its realization principle is to realize the thread interruption by modifying the interruption mark of the thread
public class InterruptDemo {<!-- --> private static int i = 0; public static void main(String[] args) throws InterruptedException {<!-- --> Thread thread = new Thread(()->{<!-- --> while(!Thread.currentThread().isInterrupted()){<!-- --> //By default, isInterrupted returns false, and becomes true through thread.interrupt i + + ; } System.out.println("final num:" + i); },"InterruptDemo"); thread. start(); Thread. sleep(1000); thread. interrupt(); } }
A blocked thread is interrupted
public class InterruptDemo {<!-- --> private static int i = 0; public static void main(String[] args) throws InterruptedException {<!-- --> Thread thread=new Thread(()->{<!-- --> while(!Thread.currentThread().isInterrupted()){<!-- --> try {<!-- --> TimeUnit. SECONDS. sleep(1); } catch (InterruptedException e) {<!-- --> System.out.println("thread interrupt"); e.printStackTrace(); //The current exception only responds to the external interrupt command, and the interrupt status of the thread will also be reset. If the thread needs to be interrupted, we need to perform an interrupt here again Thread. currentThread(). interrupt(); } } },"InterruptDemo"); thread. start(); Thread. sleep(1000); thread. interrupt(); } }
We usually use sleep, wait, join and other operations in the thread, it will throw an InterruptedException exception, why this exception is thrown, because it must be able to respond to the interrupt request initiated by other threads during the blocking period, and This response is achieved through InterruptedException
The throwing of InterruptedException does not mean that the thread must be terminated, but to remind the current thread that an interrupted operation has occurred, and how to deal with it depends on the thread itself, for example
- Catch the exception directly without any processing
- throw the exception out
- Stop the current thread and print the exception information
Thread Dump thread analysis
When we use threads, if there is a problem, how to troubleshoot?
For example, the CPU usage is high and the response is slow; the CPU usage is not high but the response is slow; the thread is deadlocked
nohup java -jar -Dserver.port=8580 thread-demo-0.0.1-SNAPSHOT.jar > localhost.log & amp;
The CPU is not high, but the response is very slow
This problem occurs when there is a deadlock, because the two threads are waiting for each other, so although the response is very slow, the cpu is not high
@GetMapping("/dead") public String dumpDeadLock(){<!-- --> Thread a = new ThreadA(); Thread b = new ThreadB(); a.start(); b. start(); return "ok"; }
public class ThreadA extends Thread {<!-- --> @Override public void run() {<!-- --> synchronized (ThreadA. class) {<!-- --> System.out.println("thread A" + Thread.currentThread().getName()); try {<!-- --> Thread. sleep(5000); } catch (InterruptedException e) {<!-- --> e.printStackTrace(); } synchronized (ThreadB. class) {<!-- --> } } } }
public class ThreadB extends Thread {<!-- --> @Override public void run() {<!-- --> synchronized (ThreadB. class) {<!-- --> System.out.println("thread A" + Thread.currentThread().getName()); try {<!-- --> Thread. sleep(1000); } catch (InterruptedException e) {<!-- --> e.printStackTrace(); } synchronized (ThreadA. class) {<!-- --> } } } }
To check the deadlock problem, follow the steps below:
- View the pid of the java process through the
jps
command - View thread logs through
jstack
If there is a deadlock situation, the Thread Dump log will definitely giveFound one Java-level deadlock:
information. As long as you find this information, you can locate the problem.
CPU is very high, and the response is very slow
If there is an infinite loop in the thread, there will be such a problem
@GetMapping("/loop") public String dumpWhile(){<!-- --> new Thread(new LoopThread()).start(); return "ok"; }
public class LoopThread implements Runnable {<!-- --> @Override public void run() {<!-- --> while (true) {<!-- --> System.out.println("Thread run..."); } } }
Steps to Troubleshoot Too High CPU
top -c
This command can dynamically display the leaderboard of processes and resource usage, so as to find the PID of the process with the highest CPU usage, assuming PID=89831top -H -p [PID]
Find the thread that consumes the most CPU in the process, get PID2=88765printf "0x%x\\
Convert the corresponding thread PID into hexadecimal
" 88765jstack 89831| grep -A 30 0x15abd
View the thread dump log, where -A 30 means to display 30 lines, 89831 means the process ID, 0x15abd means the hexadecimal thread ID
You can see from the printed dump log which method’s execution logic caused the CPU to be too high