Oh, el código que se ha estado ejecutando en la línea bancaria durante un año tiene un accidente

Inserte la descripción de la imagen aquí

Introducción

Cuando estaba en el grupo de agua el fin de semana, descubrí que un pequeño socio encontró un problema en línea

En el grupo de subprocesos, solo el estado de un subproceso es EJECUTIVO y los demás están EN ESPERA. ¿Cuáles son las posibles causas?

Inserte la descripción de la imagen aquí

El grupo de subprocesos tiene 25 subprocesos, solo un subproceso está atascado en la lectura de red, el estado es RUNNABLE y los otros subprocesos están EN ESPERA.
Inserte la descripción de la imagen aquí

Quizás algunos amigos nunca hayan usado esta herramienta. Presente brevemente esta herramienta de monitoreo de desempeño JMC. JMC es un conjunto de herramientas de monitoreo y administración derivadas de JRockit JVM. Oracle lo incluyó en el lanzamiento de JAVA 7u4 (Java 7 Update 40). En JDK, los usuarios ya no necesitan descargar por separado

Simplemente ejecute jmc en el comando

Los parámetros de configuración de inicio de la aplicación son los siguientes

-Dcom.sun.management.jmxremote.port=7091 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false

Conéctese al JMC configurado para ver varios indicadores de detección.

Originalmente, quería que este pequeño socio enviara el código y echara un vistazo, pero dijo que estaba haciendo un proyecto bancario y no estaba conectado a Internet, por lo que solo podía usar su teléfono móvil para abrir un video en la computadora. para mostrarme una descripción general. Restablezco la escena de este código Se estima que muchos socios pequeños pueden encontrar el problema a la vez, porque omití el código redundante, dejando solo el código que causará el problema.

public class BankDemo {
    
    

    public ExecutorService service = Executors.newFixedThreadPool(5);

    public static class Task implements Runnable {
    
    

        private CountDownLatch latch;

        public void setLatch(CountDownLatch latch) {
    
    
            this.latch = latch;
        }

        @SneakyThrows
        @Override
        public void run() {
    
    
            // 建立一个Socket连接发送数据
            Socket socket = new Socket("127.0.0.1",10006);
            // ...
            // 执行最后调用如下方法
            latch.countDown();
        }
    }

    // 真实的代码这里的过程为,每次往线程池里面放一批任务,这一批任务执行完毕,再放下一批任务
    // 即循环调用如下方法
    @SneakyThrows
    public void runTask(List<Task> taskList) {
    
    
        CountDownLatch latch = new CountDownLatch(5);
        taskList.forEach(item -> {
    
    
            item.setLatch(latch);
            service.submit(item);
        });
        latch.await();
    }
}

Recuerde que el hilo en el estado de ESPERA está bloqueado en el método LockSupport.park () (usando la herramienta JMC en la figura anterior)

Para escribir un episodio, este pequeño socio siempre me ha enfatizado que este código se ha estado ejecutando en línea durante un año y no ha habido ningún problema. ¿Cómo es que tiene un problema, entonces su solución es mirar siempre qué partes ha modificado, pero nunca ve el problema?

Y mi pensamiento es diferente al suyo, porque algunos errores solo aparecerán en ciertos escenarios. No crea que no hay ningún problema con el código anterior. Comience con el problema en sí.

Estado del hilo de Java

El conocimiento básico sigue siendo muy importante cuando encuentra un problema, revíselo

El estado del hilo simple se muestra en la siguiente figura.
Inserte la descripción de la imagen aquí
Hay una clase interna de enumeración State dentro del hilo Java Thread, que define el valor de enumeración del estado del hilo del lenguaje Java

  1. NUEVO (estado de inicialización)
  2. RUNNABLE (estado operativo / en ejecución)
  3. BLOQUEADO (estado bloqueado)
  4. ESPERANDO (Esperando sin límite de tiempo)
  5. TIMED_WAITING (espera por tiempo limitado)
  6. TERMINADO (estado terminal)

Java subdivide el estado de bloqueo a nivel del sistema operativo en tres estados: BLOQUEO, ESPERA y TIEMPO_ESPERA.

NUEVO: Estado nuevo , el estado en el que se crea el hilo pero no se inicia. Hay tres formas de crear un hilo

  1. Heredar la clase Thread
  2. Implementar la interfaz Runnable
  3. Implementar la interfaz invocable

Usamos más comúnmente esta forma de implementar interfaces. La diferencia entre las interfaces ejecutables y las que se pueden llamar es la siguiente

  1. Runnable no puede obtener el valor de retorno, pero Callable puede obtener el valor de retorno
  2. Runnable no puede lanzar excepciones, mientras que Callable puede lanzar excepciones

RUNNABLE (estado listo) : el estado antes de ejecutarse después de llamar al inicio
RUNNING (estado de ejecución) : el hilo se está ejecutando
BLOQUEADO (estado bloqueado) : ingrese al siguiente estado, existen las siguientes situaciones

  1. BLOQUE (bloqueo síncrono): el bloqueo está ocupado por otros hilos, como esperar para ingresar al método sincronizado o bloque de código
  2. ESPERA (bloqueo activo): ejecuta Object.wait (), Thread.join (), etc.
  3. TIMED_WAITING (esperando bloqueo): ejecute Object.wait (largo), Thread.sleep (largo), etc.

DEAD (estado de terminación) : la ejecución del hilo se completa y
finalmente se agregan varios métodos al diagrama de estado del hilo
Inserte la descripción de la imagen aquí

Restauración de escena

El hilo de ESPERA generalmente se llama uno de los siguientes tres métodos

  1. Object.wait ()
  2. Thread.join ()
  3. LockSupport.park ()

El proceso de solución de problemas es el siguiente

  1. Después de aclarar que Object.wait () y Thread.join () no se llaman en el código, básicamente se determina que el bloqueo de subprocesos causado por la clase de herramienta bajo el paquete java.util.concurrent se llama, porque el java.util paquete .concurrent Las siguientes herramientas utilizan con frecuencia LockSupport.park ()

  2. Luego, se puede determinar que el problema se debe al uso de CountDownLatch, otros subprocesos han finalizado, solo se está ejecutando un subproceso y otros subprocesos están bloqueados y esperando

  3. Entonces, ¿qué hizo este hilo RUNNABLE, por qué no ha terminado? En este momento, una imagen al comienzo del artículo señalaba la dirección, y este hilo estaba bloqueado en la lectura de la red.

  4. Dado que está atascado en la lectura de la red, no debe haber establecido el tiempo de espera de la conexión ni el tiempo de espera para la lectura. Cuando pregunté, fue lo mismo que pensé, sin configuraciones

Después de la configuración, se ejecutó localmente, y todavía se estaba ejecutando normalmente al principio, y luego arrojó directamente una excepción
Inserte la descripción de la imagen aquí
SocketTimeoutException: connect timed out (connection timed out)
SocketException: Connection reset (el servidor cerró la conexión, pero el cliente sigue leyendo datos de la conexión)

Entonces, ¿por qué el programa se ejecutó normalmente al principio? ¿Reportó esta anomalía de conexión más tarde?

  1. De hecho, el servidor es demasiado concurrente
  2. BIO realiza la solicitud de red del servidor. Una solicitud crea un hilo, que no puede admitir una alta concurrencia.

Inserte la descripción de la imagen aquí
¿En cuanto a la razón? Le pedí a mi amigo que buscara al desarrollador del servidor para confirmar que el servidor realmente se implementó usando BIO. Netty no se usa para solicitudes de red, ¡sigue siendo su rebeldía!

Esperando con interés mi artículo de seguimiento de Netty, este tipo de cosas no deben volver a suceder.

Bienvenido a seguir

Inserte la descripción de la imagen aquí

Blog de referencia

Supongo que te gusta

Origin blog.csdn.net/zzti_erlie/article/details/108681060
Recomendado
Clasificación