Resumen de las preguntas de la entrevista del grupo de subprocesos de Java [Registro de pasantías 01]

Hilo local

¿La clave es nula después de GC?

incierto.

(1) Cuando se usa new ThreadLocal<>().set(s);para definir threadlocal, si una variable no se declara en la pila para apuntar a ella, entonces solo se hace referencia débilmente a ella. Después de gc, el threadlocal se reciclará. Si la clave es nula y el valor aún está allí, causará una pérdida de memoria. Por lo tanto, asegúrese de llamar al método remove después de usar threadlocal para evitar pérdidas de memoria porque la clave es nula. .

(2) Cuando se define usando ThreadLocal<object> threadLocal = new ThreadLocal<>();el método, es equivalente a una variable threadLocal en la pila que apunta a este objeto, formando una referencia fuerte, incluso en la entrada, como clave, es una referencia débil, pero siempre hay una variable llamado "threadLocal" en la pila. Hay una fuerte referencia que apunta a él, por lo que la clave no estará vacía en este caso. Pero mientras la variable threadLocal desaparezca después de ejecutar el método donde se encuentra la variable, dejando solo una referencia débil, la clave aún se borrará y se volverá nula.

¿Por qué la clave utiliza una referencia débil?

Si usa referencias fuertes, cuando ThreadLocalla referencia del objeto (referencia fuerte) se recicla, ThreadLocalMapaún conserva ThreadLocalla referencia fuerte. Si la clave no se elimina manualmente, ThreadLocalno se reciclará. Por lo tanto, mientras el hilo actual no muera, ThreadLocalMaplos objetos referenciados no se reciclarán, lo que se puede considerar que causa Entryuna pérdida de memoria.

Mecanismo de expansión ThreadLocalMap

Al ThreadLocalMap.set()final del método, si no se han limpiado datos después de realizar el trabajo de limpieza heurística y el Entrynúmero en la matriz hash actual ha alcanzado el umbral de expansión de la lista (len*2/3), se iniciará la lógica de ejecución rehash(): aquí, se realizará el trabajo de limpieza de detección. Primero se realiza tablela limpieza desde la posición inicial hacia atrás, es posible que se borren tablealgunos datos , en este momento se decide si se debe ampliar la capacidad mediante keyjuicio .nullEntrysize >= threshold * 3/4

Echemos un vistazo al resize()método específico. Para facilitar la demostración, el tabtamaño expandido es oldLen * 2, recalcule hashla posición y luego colóquelo en una nueva tabmatriz. Si hashocurre un conflicto, busque la entryranura más cercana null. Una vez completado el recorrido, oldTabtodos los entrydatos se han puesto en el nuevo tab.

Cuando se usa ThreadLocal, los datos de copia del hilo creados en el hilo principal no se pueden compartir con el hilo secundario en un escenario asincrónico.

Para resolver este problema, también hay una clase en JDK , cuyo principio de implementación es InheritableThreadLocalllamar a un método en el hilo principal para new Thread()crear un hilo secundario y llamar Thread#inita este método Threaden el constructor. initCopie los datos del hilo principal al hilo secundario en el método .

ThreadLocalUso práctico en proyectos.

  1. Almacenar token de usuario
  2. llamada de enlace traceId

Insertar descripción de la imagen aquí

ThreadPoolEjecutor

Definición de estrategia de saturación de ThreadPoolExecutor

Si la cantidad de subprocesos que se ejecutan actualmente simultáneamente alcanza la cantidad máxima de subprocesos y la cola está llena de tareas, ThreadPoolTaskExecutordefina algunas estrategias:

  • ThreadPoolExecutor.AbortPolicy: (Predeterminado) Lanzar RejectedExecutionExceptionpara rechazar el procesamiento de nuevas tareas.
  • ThreadPoolExecutor.CallerRunsPolicy: Llama a ejecutar su propio hilo para ejecutar la tarea, es decir, executeejecuta ( run) la tarea rechazada directamente en el hilo que llamó al método, si el ejecutor ha sido cerrado, la tarea será descartada. Por lo tanto, esta estrategia reducirá la velocidad de envío de nuevas tareas y afectará el rendimiento general del programa. Puede elegir esta estrategia si su aplicación puede tolerar este retraso y necesita que se ejecuten todas las solicitudes de tareas.
  • ThreadPoolExecutor.DiscardPolicy: Las nuevas tareas no se procesan ni descartan directamente.
  • ThreadPoolExecutor.DiscardOldestPolicy: Esta política descartará la solicitud de tarea no procesada más antigua.

Dos formas de crear un grupo de subprocesos

Método 1: ThreadPoolExecutorcrear mediante constructor (recomendado).

Método 2: crear a través de Executorla clase de herramienta del marco .Executors

  1. FixedThreadPool:Este método devuelve un grupo de subprocesos con un número fijo de subprocesos. El número de subprocesos en el grupo de subprocesos siempre sigue siendo el mismo. Cuando se envía una nueva tarea, si hay subprocesos inactivos en el grupo de subprocesos, se ejecutará inmediatamente. De lo contrario, la nueva tarea se almacenará temporalmente en una cola de tareas y, cuando un subproceso esté inactivo, se procesará la tarea en la cola de tareas.
  2. SingleThreadExecutor: Este método devuelve un grupo de subprocesos con un solo subproceso. Si se envía más de una tarea al grupo de subprocesos, la tarea se guardará en una cola de tareas. Cuando el subproceso esté inactivo, las tareas en la cola se ejecutarán en orden de primero en entrar, primero en salir.
  3. CachedThreadPool: Este método devuelve un grupo de subprocesos que puede ajustar la cantidad de subprocesos según la situación real. La cantidad de subprocesos en el grupo de subprocesos es incierta, pero si hay subprocesos inactivos que se pueden reutilizar, los subprocesos reutilizables se usarán primero. Si todos los hilos están funcionando y se envía una nueva tarea, se creará un nuevo hilo para manejar la tarea. Una vez que todos los subprocesos completen la ejecución de la tarea actual, se devolverán al grupo de subprocesos para su reutilización.
  4. ScheduledThreadPool: Esto devuelve un grupo de subprocesos utilizado para ejecutar tareas después de un retraso determinado o ejecutar tareas periódicamente.

No se recomienda el método 2 porque:

FixedThreadPoolYSingleThreadExecutor : el uso es ilimitadoLinkedBlockingQueue , la longitud máxima de la cola de tareas es y se puede acumular una gran cantidad de solicitudes, lo que resulta en OOM Integer.MAX_VALUE.

CachedThreadPool: Se utiliza una cola de sincronización SynchronousQueue, que no tiene capacidad. Cuando no hay subprocesos inactivos, los subprocesos se solicitan inmediatamente. La cantidad de subprocesos permitidos para crear es Integer.MAX_VALUE. Se puede crear una gran cantidad de subprocesos, lo que resulta en OOM.

ScheduledThreadPoolYSingleThreadScheduledExecutor : La cola de bloqueo de retraso ilimitado utilizada DelayedWorkQueuese expandirá automáticamente a la mitad de la capacidad original cuando los elementos agregados estén llenos, es decir, nunca se bloqueará. La longitud máxima de la cola de tareas es, y una gran cantidad de solicitudes Integer.MAX_VALUEpueden se acumulan, lo que resulta en OOM.

DelayedWorkQueueLos elementos internos no se clasifican según el tiempo de ejecución, sino que las tareas se clasifican según la duración del retraso y se utiliza la estructura de datos interna "montón" .

Análisis del principio del grupo de subprocesos.

Insertar descripción de la imagen aquí

Ejecutable vs invocable

RunnableLas interfaces no devuelven resultados ni arrojan excepciones comprobadas, pero Callablelas interfaces sí.

La clase de herramienta Executorspuede convertir Runnableobjetos en Callableobjetos, que pertenecen al patrón de conversión.

Diferencias entre enviar y ejecutar

execute()El método se utiliza para enviar tareas que no requieren un valor de retorno, por lo que es imposible determinar si el grupo de subprocesos ejecuta correctamente la tarea;

submit()El método se utiliza para enviar tareas que requieren valores de retorno. El grupo de subprocesos devolverá un objeto FutureTaskFuture de tipo y obtendrá el valor de retorno a través del método. El método bloqueará el subproceso actual hasta que se complete la tarea . Si se utiliza el método, si la tarea no se ha ejecutado dentro del tiempo, será arrojado .Futureget()get()get(long timeout,TimeUnit unit)timeoutjava.util.concurrent.TimeoutException

apagar() VS apagarAhora()

  • shutdown():Cierre el grupo de subprocesos y el estado del grupo de subprocesos cambiará a SHUTDOWN. El grupo de subprocesos ya no acepta nuevas tareas, pero las tareas en la cola deben completarse .
  • shutdownNow(): Cierra el grupo de subprocesos y el estado del subproceso cambia STOP. El grupo de subprocesos finalizará las tareas que se están ejecutando actualmente, dejará de procesar las tareas en cola y devolverá la Lista en espera de ser ejecutada .

isTerminate() VS isShutdown()

  • isShutDownDevuelve verdadero cuando se llama shutdown()al método .
  • isTerminatedCuando shutdown()se llama al método y se completan todas las tareas enviadas, devuelve verdadero

Comparación entre ScheduledThreadPoolExecutor y Timer

  • TimerSensible a cambios en el reloj del sistema, ScheduledThreadPoolExecutorno;
  • TimerSólo hay un hilo de ejecución, por lo que las tareas de larga duración pueden retrasar otras tareas. ScheduledThreadPoolExecutorSe puede configurar cualquier número de subprocesos. ThreadFactoryAdemás, puedes tener control total sobre los hilos creados si lo deseas (proporcionando ;
    . ScheduledThreadPoolExecutorSe puede configurar cualquier número de subprocesos. ThreadFactoryAdemás, puedes tener control total sobre los hilos creados si lo deseas (proporcionando ;
  • TimerTaskUna excepción de tiempo de ejecución lanzada matará un subproceso, lo que provocará pánico Timer, es decir, la tarea programada ya no se ejecutará. ScheduledThreadExecutorNo solo detecta excepciones en tiempo de ejecución, sino que también le permite manejarlas si es necesario (anulando afterExecuteel método ThreadPoolExecutor). La tarea que genera la excepción se cancelará, pero otras tareas seguirán ejecutándose.

Supongo que te gusta

Origin blog.csdn.net/m0_63323097/article/details/130590819
Recomendado
Clasificación