[Programación concurrente] El principio básico de los subprocesos y el análisis de subprocesos de volcado de subprocesos

Fundamentos de hilos

Coloque un diagrama esquemático del subproceso:
después de que el código Java crea el subproceso, iniciamos el subproceso llamando al método, llamamos al método de subproceso.cpp para iniciar el subproceso, la capa inferior sigue siendo el subproceso operado start()por el sistema operativo create_thready el métodostart_thread
inserte la descripción de la imagen aquí

El estado de ejecución del hilo.

Durante la ejecución del subproceso, habrá varios estados diferentes. En términos generales, en Java, el estado del subproceso es un total de 6 estados, a saber,
NUEVO: estado inicial, el subproceso está construido, pero el método de inicio no ha sido llamado
** EJECUTABLE: **Estado en ejecución, el subproceso JAVA se refiere a los dos estados de listo y en ejecución en el sistema operativo como "en ejecución" **
BLOQUEADO: **Estado bloqueado, lo que indica que el subproceso entra en el estado de espera, es decir, el hilo se rinde por alguna razón El derecho a usar la CPU, el bloqueo
también se puede dividir en varias situaciones

  • Esperando el bloqueo: el subproceso en ejecución ejecuta el método de espera y jvm pondrá el subproceso actual en la cola de espera
  • Bloqueo síncrono: cuando el subproceso en ejecución adquiere el bloqueo de sincronización del objeto, si el bloqueo de sincronización está ocupado por otros bloqueos de subprocesos, jvm colocará el subproceso actual en el grupo de bloqueos.
  • Otro bloqueo: cuando el subproceso en ejecución ejecuta el método Thread.sleep o t.join, o envía una solicitud de E/S, la JVM establecerá el subproceso actual en un estado bloqueado. Cuando termina la suspensión, el subproceso de unión finaliza y el procesamiento io se completa, el hilo se reanuda

ESPERANDO: estado de espera
TIME_WAITING: estado de espera de tiempo de espera, vuelve automáticamente después del tiempo de espera
TERMINADO: estado terminado, lo que indica que la ejecución del subproceso actual se ha completado
inserte la descripción de la imagen aquí

Cómo interrumpir un hilo

Thread proporciona algunos métodos de operación de hilos, como detener, suspender, etc. Estos métodos pueden terminar un hilo o
suspender un hilo, pero no se recomienda que todos los usen. Debido a que estos métodos son métodos de interrupción forzada, se fuerza la interrupción de la mitad de la ejecución de la tarea del subproceso, lo que puede causar problemas de datos. Este comportamiento es similar a la ejecución kill -9de comandos , que es una operación insegura.

En circunstancias normales, los subprocesos no requieren intervención manual por parte del usuario. ¿Qué interrupciones de subprocesos requieren intervención externa?

  1. Hay un bucle infinito en el hilo.
  2. Hay algunas operaciones de bloqueo en el hilo, como dormir, esperar, unirse, etc.

Hay una interrupción de subproceso en bucle

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();
    }
}

Para la situación en la que hay un bucle infinito en el subproceso, debe haber una condición final en el código, y el usuario puede modificar esta condición final en otro lugar para que el subproceso pueda percibir el cambio. Al igual que el código anterior, lo cambiamos while(true)a while(flag), y luego esto flagse puede modificar externamente como una variable compartida.Después de la modificación, la condición del ciclo no se cumple y luego salimos del ciclo y finalizamos el hilo.

Java proporciona un interruptmétodo , este método es realizar la operación de interrupción del subproceso, y su principio de realización es realizar la interrupción del subproceso modificando la marca de interrupción del subproceso.

public class InterruptDemo {
    
    

    private static int i = 0;

    public static void main(String[] args) throws InterruptedException {
    
    
        Thread thread = new Thread(()->{
    
    
            while(!Thread.currentThread().isInterrupted()){
    
    
                //默认情况下isInterrupted返回false、通过thread.interrupt变成了true
                i++;
            }
            System.out.println("final num:"+ i);
        },"InterruptDemo");
        thread.start();
        Thread.sleep(1000);
        thread.interrupt();
    }

}

Se interrumpe un hilo bloqueado

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("线程中断");
                    e.printStackTrace();
                    //当前异常只是响应了外部的中断命令,同时线程的中断状态也会复位,如果需要中断该线程,我们需要在这里再执行一次中断
                    Thread.currentThread().interrupt();
                }
            }
        },"InterruptDemo");
        thread.start();
        Thread.sleep(1000);
        thread.interrupt();
    }

}

Usualmente usamos sleep, wait, join y otras operaciones en el hilo, lanzará una excepción InterruptedException, por qué se lanza esta excepción, porque debe poder responder a la solicitud de interrupción iniciada por otros hilos durante el período de bloqueo, y esto la respuesta se logra a través de InterruptedException

El lanzamiento de InterruptedException no significa que el subproceso deba terminarse, sino recordar al subproceso actual que se ha producido una operación interrumpida En cuanto a cómo tratarlo a continuación, depende del subproceso en sí, como

  1. Captura la excepción directamente sin ningún procesamiento
  2. tirar la excepción
  3. Detener el hilo actual e imprimir la información de excepción

Análisis de subprocesos de volcado de subprocesos

Cuando usamos subprocesos, si hay un problema, ¿cómo solucionarlo?
Por ejemplo, el uso de la CPU es alto y la respuesta es lenta; el uso de la CPU no es alto pero la respuesta es lenta; el subproceso está bloqueado

 nohup java -jar -Dserver.port=8580 thread-demo-0.0.1-SNAPSHOT.jar > localhost.log &

La CPU no es alta, pero la respuesta es muy lenta.

Este problema ocurre cuando hay interbloqueo, porque los dos hilos están esperando el uno al otro, por lo que aunque la respuesta es muy lenta, la cpu no está alta.

   @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) {
    
    
            }
        }
    }
}

Para verificar el problema de punto muerto, siga los pasos a continuación:

  1. Ver el pid del proceso java a través jpsdel comando
  2. Al jstackver el registro de subprocesos,
    si hay una situación de interbloqueo, el registro de volcado de subprocesos definitivamente brindará Found one Java-level deadlock:información. Siempre que encuentre esta información, podrá localizar el problema.

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

CPU alta y respuesta lenta

Si hay un bucle infinito en el hilo, habrá tal problema

 @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...");
        }
    }
}

Pasos para solucionar problemas de CPU demasiado alta

  1. top -cEste comando puede mostrar dinámicamente la lista de clasificación de procesos y uso de recursos, para encontrar el PID del proceso con el mayor uso de CPU, asumiendo PID=89831
  2. top -H -p [PID] Encuentre el subproceso que consume la mayor cantidad de CPU en el proceso y obtenga PID2 = 88765
  3. printf "0x%x\n" 88765Convierta el PID del subproceso correspondiente a hexadecimal
  4. jstack 89831| grep -A 30 0x15abdVerifique el registro de volcado de subprocesos, donde -A 30 significa mostrar 30 líneas, 89831 significa la ID del proceso y 0x15abd significa la ID hexadecimal del subproceso

Puede ver en el registro de volcado impreso qué lógica de ejecución del método provocó que la CPU fuera demasiado alta

Supongo que te gusta

Origin blog.csdn.net/qq_35448165/article/details/129706045
Recomendado
Clasificación