[Concurrent Programming] The basic principle of threads and Thread Dump thread analysis

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?

  1. There is an infinite loop in the thread
  2. 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

  1. Catch the exception directly without any processing
  2. throw the exception out
  3. 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:

  1. View the pid of the java process through the jps command
  2. View thread logs through jstack
    If there is a deadlock situation, the Thread Dump log will definitely give Found 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

  1. 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=89831
  2. top -H -p [PID] Find the thread that consumes the most CPU in the process, get PID2=88765
  3. printf "0x%x\\
    " 88765
    Convert the corresponding thread PID into hexadecimal
  4. jstack 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