análise das entrevistas do pool de threads subjacente

Tópico diagrama de classe piscina

Executor ==> ExcutorService ==> AbstractExecutorService ==> ThreadPoolExecutor para analisar.

 

  • Acima de hierarquia de herança url, o nível superior da interface é o Executor pool de threads, essa interface tem apenas um método vazio executar (comando Runnable)
  • ExecutorService herança Executor, várias grandes novo método submit (Runnable (mobilizável)), desligamento, shutDownNow etc.
  • AbstractExecutorService implementos várias interfaces ExecutorService acima método.
  • ThreadPoolExecutor herança AbstractExecutorService, para alcançar alguns dos principais métodos executar pool de threads (Runnable).

 

AbstractExecutorService

AbstractExecutorService alcançado método de envio, como segue:

enviar (tarefa mobilizável) 方法

  1. public <T> Future <T> enviar (Callable <T> tarefa) {
  2. if (tarefa == null) throw new NullPointerException ();
  3. RunnableFuture <T> ftask = newTaskFor (tarefa);
  4. executar (ftask);
  5. voltar ftask;
  6. }

newTaskFor (que pode ser chamado mobilizável) 方法

  1. protegido <T> RunnableFuture <T> newTaskFor (Callable <T> resgatável) {
  2. retornar nova FutureTask <T> (exigível);
  3. }

O acima FutureTask percebeu interfaces de RunnableFuture, RunnableFuture herda as interfaces Execut�eis e futuras. Void run apenas uma método de interface Runnable, interfaces de futuros cancelar (boolean), V boolean isDone método get () (), V get (longo tempo de espera, a unidade TimeUnit), boolean isCancelled (),.

ThreadPoolExecutor

Em seguida, o acima chamadas de método para executar AbstractExecutorService.submit (ftask), esta é para executar a ThreadPoolExecutor. Então nós temos que analisar, a fim de executar o método como um ponto de partida.

executar

  1. public void executar (comando Runnable) {
  2. if (comando == null)
  3. throw new NullPointerException ();
  4. int c = ctl.get ();
  5. if (workerCountOf (c) <corePoolSize) {
  6. if (addWorker (comando, true))
  7. Retorna;
  8. c = ctl.get ();
  9. }
  10. if (IsRunning (c) && workQueue.offer (comando)) {
  11. int reverificao = ctl.get ();
  12. if (! IsRunning (reverificação) && remove (de comando))
  13. rejeitar (comando);
  14. else if (workerCountOf (reverificação) == 0)
  15. addWorker (null, falso);
  16. }
  17. else if (! addWorker (comando, false))
  18. rejeitar (comando);
  19. }
  • Primeiro, verifique o número atual de threads de trabalho é inferior a corePoolSize, se inferior a 10, adicionar um trabalhador para lidar com essa tarefa (commadn), adicione a tarefa com êxito é retornada.
  • Se o segmento ainda está em estado de execução, ea tarefa adicionado com sucesso para a fila, a re-verificar o status de um pool de threads, pool de threads se a não-execução, exclua o trabalho da fila, o sucesso da chamada rejeitar, recusar aqui para executar de acordo com a política; se a corrente número de threads de trabalho é 0, em seguida, adicione um trabalhador (addWorker (null, false), a notar aqui, não é o mesmo como o primeiro parâmetro eo addWorker acima)
  • Se você adicionar um trabalhador não cumprir também método rejeitar.

 

addWorker

 

  1. boolean addWorker privada (Runnable firstTask, boolean core) {
  2. repetir:
  3. para (;;) {
  4. int c = ctl.get ();
  5. int rs = runStateOf (c);
  6.  
  7. // Verifique se a fila de esvaziar somente se necessário.
  8. if (rs> = desligamento &&
  9. ! (RS == SHUTDOWN &&
  10. firstTask == null &&
  11. ! workQueue.isEmpty ()))
  12. retorna falso;
  13.  
  14. para (;;) {
  15. int wc = workerCountOf (c);
  16. if (wc> = CAPACIDADE ||
  17. wc> = (? núcleo corePoolSize: maximumPoolSize))
  18. retorna falso;
  19. se (compareAndIncrementWorkerCount (c))
  20. quebrar de repetição;
  21. c = ctl.get (); ctl // Re-leitura
  22. if (runStateOf (c)! = rs)
  23. continuar de repetição;
  24. // outra CAS falhou devido a mudança workerCount; repetir loop interno
  25. }
  26. }
  27.  
  28. booleano workerStarted = false;
  29. booleano workerAdded = false;
  30. Trabalhador w = nulo;
  31. experimentar {
  32. w = trabalhador novo (firstTask);
  33. Linha T final = w.thread;
  34. if (t! = null) {
  35. definitiva ReentrantLock mainLock = this.mainLock;
  36. mainLock.lock ();
  37. experimentar {
  38. // Verifique novamente enquanto segura bloqueio.
  39. // De volta em caso de falha ThreadFactory ou se
  40. // desligado antes bloqueio adquirido.
  41. int rs = runStateOf (ctl.get ());
  42.  
  43. if (rs <SHUTDOWN ||
  44. (RS == SHUTDOWN && firstTask == nulo)) {
  45. if (t.isAlive ()) // pré-verificação de que T é inicializável
  46. throw new 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. if (workerAdded) {
  57. t.start ();
  58. workerStarted = true;
  59. }
  60. }
  61. } finalmente {
  62. if (! workerStarted)
  63. addWorkerFailed (w);
  64. }
  65. voltar workerStarted;
  66. }

(1) A lógica de decisão é mais complexa, que primeiro olhar para o

  1. if (rs> = desligamento &&
  2. ! (RS == SHUTDOWN &&
  3. firstTask == null &&
  4. ! workQueue.isEmpty ()))
  5. retorna falso;

Se o estado atual é maior do que SHUTDOWN, se a condição determinação é aparentemente ture, returnfalse direta. (Bem entendido, o pool de threads está fechado certamente não para adicionar um novo trabalhador a) Se o estado atual de menos de SHUTDOWN, se a condição juízo é falso, então ir para baixo (thread estado piscina FUNCIONAMENTO, bem entendido) Se o estado atual de igual SHUTDOWN: Se o trabalho fila firstTask é igual a nulo e tem a tarefa, é julgado se a condição for falsa, o código não retornar, continuará a correr para baixo, não é igual a zero, ou se firstTask fila de trabalho está vazia, é determinado que a condição é verdadeira, retornará false (Ye Hao entender isso, nós sabemos estado de desligamento, o pool de thread não está mais aceitando novas tarefas, mas a tarefa tem sido na fila de trabalho ou para concluir o trabalho. Portanto, se o primeiro é igual a zero, e a fila de trabalho tem a tarefa, mas também continuar a previsto. Se o oposto, não vai cair) (2) para determinar o número atual de threads de trabalho

  1. para (;;) {
  2. int wc = workerCountOf (c);
  3. if (wc> = CAPACIDADE ||
  4. wc> = (? núcleo corePoolSize: maximumPoolSize))
  5. retorna falso;
  6. se (compareAndIncrementWorkerCount (c))
  7. quebrar de repetição;
  8. c = ctl.get (); ctl // Re-leitura
  9. if (runStateOf (c)! = rs)
  10. continuar de repetição;
  11. // outra CAS falhou devido a mudança workerCount; repetir loop interno
  12. }

O número atual de threads de trabalho é nenhum parâmetro limite excede as configurações pool de segmentos, o uso de CAS para adicionar um trabalhador, e fora do exterior para o loop, continuar a executar para baixo. Caso contrário, ele retorna false, adicione o trabalhador falhar. (3) Após a conclusão da etapa acima de 12, executa uma nova Trabalhador (firstTask), Thread t = pool de threads w.thread e verificar o estado de novo, se for válido, é adicionado ao trabalhador pool de threads de trabalho atual HashSet e executa t .start. Desta vez, antes de abrir a sub-thread para executar a tarefa.

método de execução sub-thread

Passo 3 acima chamadas t.start, método executado vai abrir um sub-segmento a ser executado no trabalhador.

  1. public void run () {
  2. runWorker (este);
  3. }
  4.  
  5. definitiva runWorker vazio (trabalhador w) {
  6. Passe em peso = Thread.currentThread ();
  7. tarefa executável = w.firstTask;
  8. w.firstTask = nulo;
  9. w.unlock (); // permitir interrupções
  10. booleano completedAbruptly = true;
  11. experimentar {
  12. while (tarefa! = null || (task = getTask ())! = null) {
  13. w.lock ();
  14. // Se a piscina está parando, assegurar fio é interrompido;
  15. // se não, garantir thread não é interrompido. este
  16. // exige uma nova verificação em segundo caso de lidar com
  17. // shutdownNow corrida, enquanto compensação de interrupção
  18. if ((runStateAtLeast (ctl.get (), STOP) ||
  19. (Thread.interrupted () &&
  20. runStateAtLeast (ctl.get (), STOP))) &&
  21. ! Wt.isInterrupted ())
  22. wt.interrupt ();
  23. experimentar {
  24. BeforeExecute (em peso, tarefa);
  25. Throwable jogado = null;
  26. experimentar {
  27. task.run ();
  28. }finalmente {
  29. AfterExecute (tarefa, jogado);
  30. }
  31. } finalmente {
  32. tarefa = nulo;
  33. w.completedTasks ++;
  34. w.unlock ();
  35. }
  36. }
  37. completedAbruptly = false;
  38. } finalmente {
  39. processWorkerExit (w, completedAbruptly);
  40. }
  41. }

Acima trabalhador continuamente através do método getTask (), a tarefa de aquisição de WorkQueue, se nenhuma tarefa é adquirido, método processWorkerExit é chamado.

getTask ()

  1. privado Runnable getTask () {
  2. booleano TimedOut = false; // Será que a última poll () fora do tempo?
  3. para (;;) {
  4. int c = ctl.get ();
  5. int rs = runStateOf (c);
  6. // Verifique se a fila de esvaziar somente se necessário.
  7. if (rs> = desligamento && (rs> = PARAR || workQueue.isEmpty ())) {
  8. decrementWorkerCount ();
  9. return null;
  10. }
  11. int wc = workerCountOf (c);
  12. // Os trabalhadores sujeitos a abate?
  13. booleano cronometrada = allowCoreThreadTimeOut || wc> corePoolSize;
  14. if ((wc> maximumPoolSize || (cronometrado && TimedOut))
  15. && (wc> 1 || workQueue.isEmpty ())) {
  16. se (compareAndDecrementWorkerCount (c))
  17. return null;
  18. continuar;
  19. }
  20. experimentar {
  21. r = Execut�el cronometrado?
  22. workQueue.poll (KeepAliveTime, TimeUnit.NANOSECONDS):
  23. workQueue.take ();
  24. if (r! = null)
  25. retornar r;
  26. TimedOut = true;
  27. } Catch (repetição InterruptedException) {
  28. TimedOut = false;
  29. }
  30. }
  31. }

getTask é um método para o método de loop infinito, ele primeiro determina o estado atual do pool de threads

  1. if (rs> = desligamento && (rs> = PARAR || workQueue.isEmpty ())) {
  2. decrementWorkerCount ();
  3. return null;
  4. }

Esse julgamento também é bem compreendida, se rs == SHUTDOWN, WorkQueue está vazia, obviamente, ele deve retornar nulo diretamente, e antes do trabalho é reduzido por um trabalhador. (The return null getTask, método runWorker chama processWorkerExit atual remove do trabalhador HashSet), se rs> maior que o desligamento (correspondente ao pool de threads shutDownNow este método, a tarefa da fila de trabalho esperando não é executado), caso contrário, o pool de threads descrito no execução, continuar a executar para baixo. Em seguida, o número máximo de threads do pool de threads está definido, e se permite ou não ao longo do tempo e a linha de estado coreThread WorkQueue determina se a operação por um número CAS de fios juntos Salvar retorno nulo. Finalmente, queremos chamar a atenção para as seguintes tarefas das operações cabeça fila de trabalho de três.

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

Se ocorrer no tempo para tura (allowCoreThreadTimeOut definida para verdadeiro), e mais do que o tempo de espera ainda não atingiu a tarefa do WorkQueue r = nulo, até mesmo, neste momento, podem causar menos do que workerCount corePoolSize, o trabalhador corrente também pode ser recuperado. Se false cronometrado, a chamada de método de bloqueio para obter a tarefa de WorkQueue, newFixedThreadPool sempre chamar o método de bloqueio, de modo a alcançar sem exibir o pool de threads está fechado, mesmo se WorkQueue está vazia, mas também para manter um número fixo de segmentos de trabalho .

desligamento método (shutDownNow)

  1. Lista pública <Runnable> shutdownNow () {
  2. List <Execut�eis> tarefas;
  3. definitiva ReentrantLock mainLock = this.mainLock;
  4. mainLock.lock ();
  5. experimentar {
  6. checkShutdownAccess ();
  7. // shutDwonNow como STOP, o desligamento como SHUTDOWN
  8. advanceRunState (STOP); (advanceRunState (shutdown);)
  9. interruptWorkers ();) (interruptIdleWorkers
  10. // shutDownNow especial
  11. tarefas = drainQueue ();
  12. // desligamento callback especial ScheduledThreadPoolExecutor
  13. OnShutdown ();
  14. } finalmente {
  15. mainLock.unlock ();
  16. }
  17. tryTerminate ();
  18. voltar tarefas;
  19. }

desligamento e método diferença shutDownnNow (nível de código):

  • shutDownNow: advanceRunState (STOP), interruptWorkers desligamento: advanceRunState (desligamento), interruptIdleWorkers
  • desligamento mais uma OnShutdown (); ScheduledThreadPoolExecutor OnShutdown o método de replicação.
  • métodos shutDownNow trabalhar fila de tarefa incompleta.
  • interruptIdleWorkers

interruptIdleWorkers 与 interruptWorkers

(1) shutDownNow

  1. interruptWorkers private void () {
  2. definitiva ReentrantLock mainLock = this.mainLock;
  3. mainLock.lock ();
  4. experimentar {
  5. for (Trabalhador w: trabalhadores)
  6. w.interruptIfStarted ();
  7. } finalmente {
  8. mainLock.unlock ();
  9. }
  10. }

Obviamente, este é interrompido todos os segmentos (2) o desligamento

  1. interruptIdleWorkers private void (boolean onlyOne) {
  2. definitiva ReentrantLock mainLock = this.mainLock;
  3. mainLock.lock ();
  4. experimentar {
  5. for (Trabalhador w: trabalhadores) {
  6. Rosca t = w.thread;
  7. if (! t.isInterrupted () && w.tryLock ()) {
  8. experimentar {
  9. t.interrupt ();
  10. } Catch (SecurityException ignorar) {
  11. } finalmente {
  12. w.unlock ();
  13. }
  14. }
  15. se (onlyOne)
  16. pausa;
  17. }
  18. } finalmente {
  19. mainLock.unlock ();
  20. }
  21. }

parâmetros onlyOne nota, esta é apenas na chamada dentro tryTerminate () chama o método interruptIdleWorkers (true), os outros casos são interruptIdleWorkers (falsos), então para o método de desligamento, mas também tentar quebrar rosca interrompida nem tudo tem sido. 3) tryTerminate tryTerminate método acima mencionado em (2), este método vai olhar para o próximo

  1. última vazio tryTerminate () {
  2. para (;;) {
  3. int c = ctl.get ();
  4. se (IsRunning (c) ||
  5. runStateAtLeast (c, arrumar) ||
  6. (RunStateOf (c) == SHUTDOWN &&! WorkQueue.isEmpty ()))
  7. Retorna;
  8. if (workerCountOf (c)! = 0) {// elegível para terminar
  9. interruptIdleWorkers (apenas_um);
  10. Retorna;
  11. }
  12.  
  13. definitiva ReentrantLock mainLock = this.mainLock;
  14. mainLock.lock ();
  15. experimentar {
  16. se (ctl.compareAndSet (c, ctlOf (arrumar, 0))) {
  17. experimentar {
  18. terminada ();
  19. } finalmente {
  20. ctl.set (ctlOf (TERMINADO, 0));
  21. termination.signalAll ();
  22. }
  23. Retorna;
  24. }
  25. } finalmente {
  26. mainLock.unlock ();
  27. }
  28. // outra repetição no CAS falhou
  29. }
  30. }

Como pode ser visto a partir do código acima, vazio, se o número de threads de trabalho do estado pool de threads é SHUTDOWN, WorkQueue pool de threads é 0 ou o estado de paragem, o número de segmento de trabalho 0, pool de threads acabará por ter de estado terminado e acorda todos porque a chamada awaitTermination () método bloqueia em termination.awaitNanos (nanos) não acordar o segmento.

  1. boolean awaitTermination público (longo tempo de espera, a unidade TimeUnit)
  2. lança InterruptedException {
  3. longo nanos = unit.toNanos (timeout);
  4. definitiva ReentrantLock mainLock = this.mainLock;
  5. mainLock.lock ();
  6. experimentar {
  7. para (;;) {
  8. if (runStateAtLeast (ctl.get (), TERMINADO))
  9. return true;
  10. se (nanos <= 0)
  11. retorna falso;
  12. nanos = termination.awaitNanos (nanos);
  13. }
  14. } finalmente {
  15. mainLock.unlock ();
  16. }
  17. }

TryTerminate acima método, addWorkerFailed (), processWorkerExit (), desligamento (), shutDownNow (), método remove (tarefa Execut�el) irá ser chamado para.

5 estados para explicar o pool de threads

O acima indicado do estado frequentemente em execução do pool de threads, uma breve explicação aqui.

  1. static final int privado de rolamento = -1 << COUNT_BITS;
  2. SHUTDOWN private static final int = 0 << COUNT_BITS;
  3. PARAR private static final int = 1 << COUNT_BITS;
  4. Arrumar private static final int = 2 << COUNT_BITS;
  5. int private static final TERMINADO = 3 << COUNT_BITS;

A definição de estados

  • FUNCIONAMENTO: novas tarefas, tarefas de processamento em WorkQueue.
  • SHUTDOWN: não aceitar novas tarefas, mas continuará a completar a tarefa WorkQueue
  • STOP: não aceitar a nova tarefa não trata WorkQueue tarefa inacabada, tentar quebrar todas as tarefas em execução
  • Arrumar: todas as tarefas foram concluídas, o número de threads de trabalho é 0, o estado pool de threads vai se tornar arrumar chamará terminado () método.
  • TERMINADO EM: terminado () método tem sido concluída

conversão de cinco estados

  • FUNCIONAMENTO -> desligamento: desligamento call () método, talvez implícito no método finalize ()
  • (Executando ou desligamento) -> STOP: chamada de método shutdownNow ()
  • SHUTDOWN -> arrumar: WorkQueue e piscina estão vazios
  • STOP -> arrumar: piscina está vazia
  • Arrumar -> TERMINADO: terminado () 方法 完成

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

Publicado 277 artigos originais · Louvor obteve 65 · vista 380 000 +

Acho que você gosta

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