Prefacio
En la programación de múltiples subprocesos, no es realista asignar un hilo a cada tarea, y el consumo de recursos y los recursos de la creación de hilos son muy altos. Los piscinas de hilos surgieron y se convirtieron en una herramienta poderosa para que podamos administrar hilos. A través de la interfaz del Ejecutor, Java proporciona un método estándar para desacoplar el proceso de envío de tareas y ejecutar el proceso, y utiliza Runnable para representar la tarea.
A continuación, analicemos la implementación del marco del grupo de hilos Java ThreadPoolExecutor.
El siguiente análisis se basa en JDK1.7
ciclo vital
En ThreadPoolExecutor , los 3 bits superiores de capacidad se utilizan para representar el estado en ejecución, que son:
1. Running: Reciba nuevas tareas y procesa tareas en la cola de tareas
2.Shutdown: tareas que no reciben nuevas tareas pero manejan las colas de tareas
3.stop: no se reciben nuevas tareas, no se publica la cola de tareas y todas las tareas en progreso se interrumpen al mismo tiempo
4.Tidia: todas las tareas se han terminado, el número de hilos de trabajadores es 0. Cuando se alcanza este estado, se terminará () se ejecutará.
5.Terminado: terminado () ha sido ejecutado
Diagrama de transición estatal
Las clases atómicas se utilizan para representar bits de estado en Threadpoolexecutor
Private final AtomicInteger CTL = nuevo AtomicInteger (CTLOF (Running, 0));
Modelo de piscina de hilos
Parámetros del núcleo
CorePoolSize: Número mínimo de hilos de trabajadores vivos (si se establece TockCorethreadTimeOut, entonces este valor es 0)
MaximumumpondSize: el número máximo de hilos, limitado por la capacidad
KeepAlivetime: el tiempo de supervivencia del hilo correspondiente, la unidad de tiempo se especifica mediante TimeUnit
WorkQueue: cola de trabajo, almacenamiento de tareas que se ejecutarán
DelechExecutionHandler: Rechazar la política, la capacidad máxima del grupo de subprocesos se activará después de que el grupo de subprocesos esté lleno: los primeros tres bits de capacidad se usan como bits de bandera, es decir, la capacidad máxima del hilo del trabajador es (2^29) -1
Cuatro modelos
CachedThreadPool: una piscina de hilo en caché. Si el tamaño actual del grupo de subprocesos excede los requisitos de procesamiento, el hilo inactivo se reciclará. Cuando aumenta la demanda, se pueden agregar nuevos hilos. No hay límite en el tamaño del grupo de hilos.
FixedThreadPool: un grupo de roscas de tamaño fijo. Al enviar una tarea, se crea un hilo hasta que se alcanza el número máximo de grupos de subprocesos. En este momento, el tamaño del grupo de hilos ya no cambiará.
Singlethreadpool: un grupo de hilos de un solo hilo, que tiene solo un hilo de trabajador para ejecutar tareas. Puede garantizar que las tareas se ejecuten en serie en el orden en que están en la cola. Si este hilo termina anormalmente, se creará un nuevo hilo para ejecutar tareas.
ProchuledThreadPool: un grupo de subprocesos de tamaño fijo y realiza tareas de manera retrasada o cronometrada, similar al temporizador.
Ejecutar la ejecución de la tarea
Lógica del núcleo:
1. El número actual de subprocesos <corePoolSize, abra directamente el nuevo subproceso central para ejecutar la tarea addWorker (comando, verdadero)
2. Número actual de hilos> = corePoolSize, y la tarea se agrega con éxito a la cola de trabajo
1). Verifique si el estado actual del grupo de subprocesos está en funcionamiento
2). Si no, la tarea es rechazada
3). Si es así, determine si el número actual de subprocesos es 0. Si es 0, agregue un hilo de trabajador.
3. Encienda la tarea de ejecución de hilo normal addWorker (comando, falso) y rechace la tarea si no se inicia. Del análisis anterior, podemos resumir las cuatro etapas de la operación del grupo de subprocesos:
1) .PoolSize <corePoolSize y la cola está vacía. Se creará un nuevo hilo para procesar las tareas enviadas.
2) .PoolSize == CorePoolSize. En este momento, la tarea presentada ingresa a la cola de trabajo. El hilo del trabajador obtiene la ejecución de la tarea de la cola. En este momento, la cola no está vacía y no está llena.
3) .PoolSize == CorePoolSize y la cola está llena. También se creará un nuevo hilo para procesar la tarea enviada, pero PoolSize <maxpoolSize
4) .PoolSize == maxpoolSize y la cola está llena, la política de rechazo se activará
Política de rechazo <Br /> mencionamos anteriormente que si una tarea no se puede ejecutar, será rechazada. RecheedExecutionHandler es la interfaz para manejar tareas rechazadas. Aquí hay cuatro estrategias de rechazo.
Abortpolicy: política predeterminada, rescindir la tarea, tirar rechazadoxception
Callerrunspolicy: ejecute la tarea actual en el hilo de la persona que llama sin lanzar excepciones
Descartepolicy: deseche la política, deseche directamente la tarea y no arroje excepciones
DI Scandolderspolicy: abandone la tarea más antigua, ejecute la tarea actual y no arroje excepciones
Trabajador en la piscina de hilos
El trabajador hereda de abstractqueedsynchronizer y ejecutable. El primero proporciona al trabajador la función de bloqueo, y el segundo ejecuta el método principal de trabajador de subprocesos de trabajadores (trabajador W) (ejecución de tareas de SNAP desde la cola de tareas). Las referencias de los trabajadores se encuentran en la recolección de trabajadores y están protegidas por Mainlock.
Private final Reentrantlock Mainlock = new ReentrantLock ();
Hashset final privado <trabajador> trabajadores = new Hashset <VROPER> ();
Función central Runworker
La siguiente es la lógica simplificada, Nota: La ejecución de cada subproceso de trabajador ejecuta las siguientes funciones
Final void runworker (trabajador w) {hilo wt = thread.currentThread (); Tarea runnable = w.firsttask; w.firsttask = null; while (tarea! = null || (tarea = getTask ())! = null) {w.lock (); ANTEREXECUTE (WT, tarea); task.run (); After Execute (tarea, lanzado); w.unlock (); } ProcessWorkerExit (w, completado de manera informal);} 1. Obtenga la tarea de GetTask ()
2. Bloquea al trabajador
3. Ejecutar antes de EXEXECUTE (WT, Tarea), que es el método de extensión proporcionado por ThreadPoolExecutor a subclases
4. Ejecute la tarea. Si el trabajador ha configurado la primera tarea, la primera tarea se ejecutará primero y solo una vez.
5. Ejecutar AfterExCute (tarea, lanzado);
6. Desbloquear al trabajador
7. Si la tarea obtenida es nula, cierre al trabajador
Obtenga la tarea GetTask
La cola de tareas dentro del grupo de hilos es una cola de bloqueo, que se pasa durante la construcción.
BLOCKINGQUEUE FINAL PRIVADO <Runnable> WorkQueue;
GetTask () obtiene la tarea de la cola de tareas, admite el bloqueo y el tiempo de espera esperando tareas. Cuatro situaciones harán que se devuelva NULL y el trabajador está cerrado.
1. El número de hilos existentes excede el número máximo de hilos
2. La piscina de hilo está en estado de parada
3. El grupo de hilos está en estado de cierre y la cola de trabajo está vacía
4. Tiempo de espera de la tarea de espera de hilo, y el número de subprocesos excede el número de hilos retenidos
Lógica del núcleo: horario o bloqueando la tarea de espera en la cola de bloqueo. La tarea de espera programada hará que el hilo del trabajador se cierre.
Timed = todcorethreadtimeout || wc> corepoolSize; runnable r = cronometrado? WorkQueue.Poll (KeepAlivetime, TimeUnit.nanoseConds): WorkQueue.take ();
Esperar una tarea pasará tiempo en dos casos:
1. Permita que los hilos principales esperen el tiempo de espera, es decir, enterodcorethreadtimeout (verdadero)
2. El hilo actual es un hilo normal, en este momento wc> corePoolSize
La cola de trabajo usa Bloquingqueue, por lo que no lo expandiré aquí. Escribiré un análisis detallado más adelante.
Resumir
ThreadPoolExecutor se basa en el modelo de consumidor productor. La operación de enviar tareas es equivalente al productor, y el hilo de ejecutar tareas es equivalente al consumidor.
Los ejecutores proporcionan cuatro métodos para construir el modelo de grupo de hilos basado en ThreadPoolExecutor. Además, podemos heredar directamente ThreadPoolExecutor y reescribir los métodos After Execute y After EXECUTE para personalizar el proceso de ejecución de la tarea del grupo de subprocesos.
El uso de colas limitadas o colas ilimitadas debe considerarse de acuerdo con la situación específica, y el tamaño de la cola de trabajo y el número de hilos también deben considerarse cuidadosamente.
Se recomienda que la política de rechazo utilice CallerrunSpolicy, que no abandona la tarea ni arroja una excepción, sino que recae en la tarea al hilo de la persona que llama para su ejecución.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.