análisis de las entrevistas del grupo de subprocesos subyacente

diagrama de clases de grupo de subprocesos

Ejecutor ==> ExcutorService ==> AbstractExecutorService ==> ThreadPoolExecutor analizar.

 

  • Por encima de jerarquía de herencia url, el nivel superior de la interfaz es el ejecutor grupo de subprocesos, esta interfaz tiene solamente ejecutar un hueco método (comando Ejecutable)
  • ExecutorService herencia Ejecutor, varios método nuevo e importante presentar (Ejecutable (rescatable)), apagado, shutDownNow etc.
  • implementos AbstractExecutorService varias interfaces ExecutorService anterior método.
  • ThreadPoolExecutor herencia AbstractExecutorService, para lograr algunos de los principales métodos de ejecutar grupo de subprocesos (Ejecutable).

 

AbstractExecutorService

AbstractExecutorService logra presentar método, como sigue:

presentar (tarea que se puede llamar) 方法

  1. público <T> Futuro <T> enviar (rescatable <T> tarea) {
  2. si (tarea == null) throw new NullPointerException ();
  3. RunnableFuture <T> ftask = newTaskFor (tarea);
  4. ejecutar (ftask);
  5. volver ftask;
  6. }

newTaskFor (exigible Callable) 方法

  1. protegido <T> RunnableFuture <T> newTaskFor (Callable <T> exigible) {
  2. volver nueva FutureTask <T> (exigible);
  3. }

Lo anterior se dio cuenta de las interfaces FutureTask RunnableFuture, RunnableFuture hereda las interfaces Ejecutables y futuras. void run solamente un método de interfaz Ejecutable, las interfaces futuras Cancelar (booleano), V método isDone boolean () get (), get V (largo tiempo de espera, la unidad de TimeUnit), boolean isCancelled (),.

ThreadPoolExecutor

Luego de lo anterior AbstractExecutorService.submit llamadas de método a ejecutar (ftask), esto es para ejecutar el ThreadPoolExecutor. Entonces tenemos que analizar con el fin de ejecutar el método como punto de partida.

ejecutar

  1. public void ejecutar (comando Ejecutable) {
  2. si (comando == null)
  3. arrojar nueva NullPointerException ();
  4. int c = ctl.get ();
  5. si (workerCountOf (c) <corePoolSize) {
  6. si (addWorker (mando, true))
  7. regreso;
  8. c = ctl.get ();
  9. }
  10. si (isRunning (c) && workQueue.offer (comando)) {
  11. int? Servicios = ctl.get ();
  12. if (! IsRunning (? Servicios) && remove (comando))
  13. rechazar (comando);
  14. else if (workerCountOf (? Servicios) == 0)
  15. addWorker (null, false);
  16. }
  17. else if (! addWorker (mando, falso))
  18. rechazar (comando);
  19. }
  • En primer lugar, compruebe el número actual de subprocesos de trabajo es inferior a corePoolSize, si es menor de 10, añadir un trabajador para manejar esta tarea (commadn), añadir la tarea se devuelve correctamente.
  • Si el hilo está todavía en estado de ejecución, y la tarea añadida a la cola, la re-comprobar el estado de un grupo de subprocesos, grupo de subprocesos si el que no se corre, elimine el trabajo de la cola, el éxito de la llamada rechazar, negarse aquí para llevar a cabo de acuerdo con la política; si la corriente número de subprocesos de trabajo es 0, entonces añadir un trabajador (addWorker (null, false), señalar aquí, no es el mismo que el primer parámetro y el addWorker arriba)
  • Si se agrega un trabajador no puede realizar también rechazar método.

 

addWorker

 

  1. addWorker boolean privado (Ejecutable firstTask, núcleo boolean) {
  2. procesar de nuevo:
  3. para (;;) {
  4. int c = ctl.get ();
  5. int rs = runStateOf (c);
  6.  
  7. // Comprobar si cola vacía sólo si es necesario.
  8. si (rs> = APAGADO &&
  9. ! (Rs == SHUTDOWN &&
  10. firstTask == null &&
  11. ! workQueue.isEmpty ()))
  12. falso retorno;
  13.  
  14. para (;;) {
  15. int wc = workerCountOf (c);
  16. si (wc> = CAPACIDAD ||
  17. WC> = (? núcleo corePoolSize: maximumPoolSize))
  18. falso retorno;
  19. si (compareAndIncrementWorkerCount (c))
  20. romper reintento;
  21. c = ctl.get (); CTL lectura Re //
  22. if (runStateOf (c)! = rs)
  23. continuar reintento;
  24. // else CAS falló debido al cambio workerCount; reintentar bucle interior
  25. }
  26. }
  27.  
  28. boolean workerStarted = false;
  29. boolean workerAdded = false;
  30. Trabajador w = null;
  31. tratar {
  32. w = nuevo trabajador (firstTask);
  33. Tema final de t = w.thread;
  34. si (t! = null) {
  35. última ReentrantLock mainLock = this.mainLock;
  36. mainLock.lock ();
  37. tratar {
  38. // Volver a revisar mientras se mantiene la cerradura.
  39. // Volver a cabo en caso de fallo o si ThreadFactory
  40. // cerrar antes adquirió bloqueo.
  41. int rs = runStateOf (ctl.get ());
  42.  
  43. si (rs <SHUTDOWN ||
  44. (Rs == SHUTDOWN && firstTask == null)) {
  45. si (t.isAlive ()) // comprobación anterior que T es iniciable
  46. arrojar nueva IllegalThreadStateException ();
  47. workers.add (w);
  48. int s = workers.size ();
  49. if (s)> largestPoolSize
  50. = LargestPoolSize s;
  51. workerAdded = true;
  52. }
  53. } finalmente {
  54. mainLock.unlock ();
  55. }
  56. si (workerAdded) {
  57. t.Start ();
  58. workerStarted = true;
  59. }
  60. }
  61. } finalmente {
  62. if (! workerStarted)
  63. addWorkerFailed (w);
  64. }
  65. volver workerStarted;
  66. }

(1) La lógica de decisión es más compleja, lo primero que mira en el

  1. si (rs> = APAGADO &&
  2. ! (Rs == SHUTDOWN &&
  3. firstTask == null &&
  4. ! workQueue.isEmpty ()))
  5. falso retorno;

Si el estado actual es mayor que de apagado, si la condición de determinación es aparentemente tura, returnfalse directa. (Bien entendido, el grupo de subprocesos se cierra luego, no para añadir un nuevo trabajador a) Si el estado actual de menos de apagado, si la condición juicio es falsa, y luego ir hacia abajo (hilo Estado correr en una alberca, bien entendido) Si el estado actual de la igualdad APAGADO: Si la cola de trabajo firstTask es igual a cero y tiene la tarea, se juzga si la condición es falsa, el código no regresa, se continuará ejecutando desde abajo; no es igual a cero, o si la cola de trabajo firstTask está vacía, se determina que la condición es verdadera, se devuelve falso (Ye Hao entender esto, sabemos estado de cierre, el grupo de subprocesos no acepta más nuevas tareas, pero la tarea ha estado en la cola de trabajo o para completar el trabajo. por lo tanto, si la primera es igual a cero, y la cola de trabajo tiene la tarea, sino también seguir establecido. en caso contrario, no va a ir hacia abajo) (2) para determinar el número actual de subprocesos de trabajo

  1. para (;;) {
  2. int wc = workerCountOf (c);
  3. si (wc> = CAPACIDAD ||
  4. WC> = (? núcleo corePoolSize: maximumPoolSize))
  5. falso retorno;
  6. si (compareAndIncrementWorkerCount (c))
  7. romper reintento;
  8. c = ctl.get (); CTL lectura Re //
  9. if (runStateOf (c)! = rs)
  10. continuar reintento;
  11. // else CAS falló debido al cambio workerCount; reintentar bucle interior
  12. }

El número actual de subprocesos de trabajo hay ningún parámetro límite excede la configuración del grupo de hilo, el uso de CAS añadir un trabajador, y fuera del exterior de bucle, continuará funcionando hacia abajo. De lo contrario, devuelve falso, añadir el trabajador no. (3) Después de la terminación de la etapa de 12 anterior, lleva a cabo un nuevo trabajador (firstTask), hilo t = grupo de subprocesos w.thread y comprobar el estado de nuevo, si es válido, se añade a la corriente trabajador grupo de subprocesos de trabajo HashSet y ejecuta t .start. Esta vez antes de abrir el sub-hilo para realizar la tarea.

método run Sub-hilo

Paso 3 anterior llamadas t.Start, método de gestión se abrirá un sub-hilo para funcionar en Trabajador.

  1. public void run () {
  2. runWorker (this);
  3. }
  4.  
  5. última runWorker void (Trabajador w) {
  6. Hilo wt = Thread.currentThread ();
  7. tarea Ejecutable = w.firstTask;
  8. w.firstTask = null;
  9. w.unlock (); // permitir interrupciones
  10. boolean completedAbruptly = true;
  11. tratar {
  12. mientras que (tarea! = null || (task = getTask ())! = null) {
  13. w.lock ();
  14. // Si la piscina está parando, asegúrese de hilo se interrumpe;
  15. // hilo si no es así, garantizar que no se interrumpa. Esta
  16. // requiere es una comprobación en el segundo caso, para hacer frente a
  17. // shutdownNow carrera, mientras interrupción de compensación
  18. if ((runStateAtLeast (ctl.get (), STOP) ||
  19. (Thread.interrupted () &&
  20. runStateAtLeast (ctl.get (), STOP))) &&
  21. ! Wt.isInterrupted ())
  22. wt.interrupt ();
  23. tratar {
  24. BeforeExecute (wt, tarea);
  25. Throwable arrojado = null;
  26. tratar {
  27. task.run ();
  28. }finalmente {
  29. afterExecute (tarea, torcer);
  30. }
  31. } finalmente {
  32. tarea = null;
  33. w.completedTasks ++;
  34. w.unlock ();
  35. }
  36. }
  37. completedAbruptly = false;
  38. } finalmente {
  39. processWorkerExit (w, completedAbruptly);
  40. }
  41. }

Por encima de los trabajadores de forma continua a través del método getTask (), la tarea de adquisición de WorkQueue, si se adquiere ninguna tarea, se llama al método processWorkerExit.

getTask ()

  1. Ejecutable getTask privada () {
  2. boolean timedOut = false; // ¿El último sondeo () el tiempo de espera?
  3. para (;;) {
  4. int c = ctl.get ();
  5. int rs = runStateOf (c);
  6. // Comprobar si cola vacía sólo si es necesario.
  7. si (rs> = APAGADO && (rs> = PARADA || workQueue.isEmpty ())) {
  8. decrementWorkerCount ();
  9. nula regresar;
  10. }
  11. int wc = workerCountOf (c);
  12. // ¿Son los trabajadores sujetos a sacrificar?
  13. boolean temporizada = allowCoreThreadTimeOut || WC> corePoolSize;
  14. if ((wc> || maximumPoolSize (cronometrado && timedOut))
  15. && (wc> 1 || workQueue.isEmpty ())) {
  16. si (compareAndDecrementWorkerCount (c))
  17. nula regresar;
  18. Seguir;
  19. }
  20. tratar {
  21. r = Ejecutable cronometrado?
  22. workQueue.poll (KeepAliveTime, TimeUnit.NANOSECONDS):
  23. workQueue.take ();
  24. si (r! = null)
  25. r retorno;
  26. timedOut = true;
  27. } Catch (reintento InterruptedException) {
  28. timedOut = false;
  29. }
  30. }
  31. }

getTask es un método para el método de bucle infinito, lo primero determina el estado actual de grupo de subprocesos

  1. si (rs> = APAGADO && (rs> = PARADA || workQueue.isEmpty ())) {
  2. decrementWorkerCount ();
  3. nula regresar;
  4. }

Este juicio también se entiende bien, si rs == APAGADO, WorkQueue está vacía, es obvio que debe devolver directamente nula, y antes de que el trabajo se reduce por un trabajador. (El retorno nula getTask, método runWorker llama actual Quitar processWorkerExit del trabajador HashSet); si rs> mayor que el SHUTDOWN (que corresponde a la agrupación de hebras shutDownNow este método, la tarea cola de trabajo de espera no se ejecuta), de lo contrario, el grupo de subprocesos se describe en corriendo, seguir circulando hacia abajo. Entonces, el número máximo de hilos de la piscina del hilo no es actualmente, y si para permitir el paso del tiempo y la línea de estado coreThread WorkQueue determina si la operación por un número CAS de hilos juntos Guardar retorno nulo. Por último, queremos llamar la atención a las siguientes tareas de la cola de trabajo de tres operaciones en la cabeza.

  1. r = Ejecutable cronometrado?
  2. workQueue.poll (KeepAliveTime, TimeUnit.NANOSECONDS):
  3. workQueue.take ();

Si el tiempo de tura (allowCoreThreadTimeOut establece en true), y más que el tiempo de espera no ha alcanzado todavía la tarea de la WorkQueue r = null, incluso en este momento, puede causar menos de workerCount corePoolSize, el trabajador actual también puede ser recuperado. Si es falso cronometrada, método de bloqueo de la llamada para obtener la tarea de WorkQueue, newFixedThreadPool siempre llamará al método de bloqueo, a fin de lograr sin que se muestre el grupo de subprocesos está cerrado, incluso si WorkQueue está vacía, sino también para mantener un número fijo de subprocesos de trabajo .

SHUTDOWN método (shutDownNow)

  1. Lista pública <Ejecutable> shutdownNow () {
  2. List <> Ejecutables tareas;
  3. última ReentrantLock mainLock = this.mainLock;
  4. mainLock.lock ();
  5. tratar {
  6. checkShutdownAccess ();
  7. // shutDwonNow como la detención, el apagado como SHUTDOWN
  8. advanceRunState (STOP); (advanceRunState (SHUTDOWN);)
  9. interruptWorkers (); (interruptIdleWorkers)
  10. // especial shutDownNow
  11. tareas = drainQueue ();
  12. // Shutdown especial ScheduledThreadPoolExecutor devolución de llamada
  13. onShutdown ();
  14. } finalmente {
  15. mainLock.unlock ();
  16. }
  17. tryTerminate ();
  18. tareas regresar;
  19. }

apagado y método de diferencia shutDownnNow (nivel de código):

  • shutDownNow: advanceRunState (STOP), interruptWorkers SHUTDOWN: advanceRunState (apagado), interruptIdleWorkers
  • SHUTDOWN más un onShutdown (); ScheduledThreadPoolExecutor onShutDown el método de replicación.
  • shutDownNow métodos funcionan cola de tareas sin terminar.
  • interruptIdleWorkers

interruptIdleWorkers 与 interruptWorkers

(1) shutDownNow

  1. interruptWorkers private void () {
  2. última ReentrantLock mainLock = this.mainLock;
  3. mainLock.lock ();
  4. tratar {
  5. para (trabajador w: trabajadores)
  6. w.interruptIfStarted ();
  7. } finalmente {
  8. mainLock.unlock ();
  9. }
  10. }

Obviamente, esto se interrumpe todos los hilos (2) de apagado

  1. interruptIdleWorkers private void (booleano ONLYONE) {
  2. última ReentrantLock mainLock = this.mainLock;
  3. mainLock.lock ();
  4. tratar {
  5. para (Trabajador w: trabajadores) {
  6. Thread t = w.thread;
  7. if (! t.isInterrupted () && w.tryLock ()) {
  8. tratar {
  9. t.interrupt ();
  10. } Catch (SecurityException ignore) {
  11. } finalmente {
  12. w.unlock ();
  13. }
  14. }
  15. si (OnlyOne)
  16. descanso;
  17. }
  18. } finalmente {
  19. mainLock.unlock ();
  20. }
  21. }

parámetros ONLYONE nota, esto es sólo en la llamada dentro tryTerminate () llama al método interruptIdleWorkers (verdadero), otros casos son interruptIdleWorkers (falsos), por lo que para el método de apagado del PC, sino que también tratan de romper el hilo interrumpido de todo no lo ha sido. 3) tryTerminate tryTerminate método mencionado anteriormente en (2), este método se verá en la siguiente

  1. última tryTerminate void () {
  2. para (;;) {
  3. int c = ctl.get ();
  4. si (isRunning (c) ||
  5. runStateAtLeast (c, poner en orden) ||
  6. (RunStateOf (c) == PARADA &&! WorkQueue.isEmpty ()))
  7. regreso;
  8. si (workerCountOf (c)! = 0) {// elegible para terminar
  9. interruptIdleWorkers (only_one);
  10. regreso;
  11. }
  12.  
  13. última ReentrantLock mainLock = this.mainLock;
  14. mainLock.lock ();
  15. tratar {
  16. si (ctl.compareAndSet (c, ctlOf (poner en orden, 0))) {
  17. tratar {
  18. terminado();
  19. } finalmente {
  20. ctl.set (ctlOf (terminada, 0));
  21. termination.signalAll ();
  22. }
  23. regreso;
  24. }
  25. } finalmente {
  26. mainLock.unlock ();
  27. }
  28. // else reintento de CAS fallado
  29. }
  30. }

Como puede verse en el código anterior, vacío, si el número de subprocesos de trabajo el estado del grupo de subprocesos es APAGADO, grupo de subprocesos WorkQueue es 0 o el estado STOP, el número de subproceso de trabajo 0, grupo de subprocesos con el tiempo se tiene que estado terminado, y se despierta todos debido a que los bloques de método llamado awaitTermination () en termination.awaitNanos (nanos) no ha despertar el hilo.

  1. awaitTermination pública booleano (largo tiempo de espera, la unidad TimeUnit)
  2. lanza InterruptedException {
  3. largo nanos = unit.toNanos (tiempo de espera);
  4. última ReentrantLock mainLock = this.mainLock;
  5. mainLock.lock ();
  6. tratar {
  7. para (;;) {
  8. si (runStateAtLeast (ctl.get (), terminado))
  9. return true;
  10. si (nanos <= 0)
  11. falso retorno;
  12. nanos = termination.awaitNanos (nanos);
  13. }
  14. } finalmente {
  15. mainLock.unlock ();
  16. }
  17. }

TryTerminate anterior método, addWorkerFailed (), processWorkerExit (), apagado (), shutDownNow (), el método remove (tarea Ejecutable) será llamado a.

5 estados para explicar la agrupación de hebras

Lo anterior estado de frecuencia de funcionamiento de la agrupación de hebras, una breve explicación aquí.

  1. private static final int RUNNING = -1 << COUNT_BITS;
  2. final privado int estática APAGADO = 0 << COUNT_BITS;
  3. final privado int PARADA estática = 1 << COUNT_BITS;
  4. final privado int poner en orden estático = 2 << COUNT_BITS;
  5. private static final int TERMINADA = 3 << COUNT_BITS;

La definición de los estados

  • RUNNING: nuevas tareas, las tareas de procesamiento en WorkQueue.
  • APAGADO: no aceptar nuevas tareas, pero continuará para completar la tarea WorkQueue
  • STOP: no aceptar la nueva tarea no se ocupa de tareas sin terminar WorkQueue, tratar de romper todas las tareas en ejecución
  • Poner en orden: todas las tareas se han completado, el número de subprocesos de trabajo es 0, el estado del grupo de subprocesos se convertirá en poner en orden será llamada al método () terminado.
  • Terminación: terminado método () se ha completado

conversión de cinco estados

  • RUNNING -> APAGADO: Método de apagado de llamada (), tal vez implícita en el método finalize ()
  • (En funcionamiento o parada) -> STOP: método llamado shutdownNow ()
  • PARO -> Poner en orden: WorkQueue y la piscina están vacías
  • STOP -> Poner en orden: la piscina está vacía
  • Poner en orden -> Terminación: terminado () 方法 完成

Fuente: http://yeming.me/2016/05/07/threadPool1/

Publicados 277 artículos originales · ganado elogios 65 · vistas 380 000 +

Supongo que te gusta

Origin blog.csdn.net/ailiandeziwei/article/details/104749570
Recomendado
Clasificación