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) 方法
- public <T> Future <T> enviar (Callable <T> tarefa) {
- if (tarefa == null) throw new NullPointerException ();
- RunnableFuture <T> ftask = newTaskFor (tarefa);
- executar (ftask);
- voltar ftask;
- }
newTaskFor (que pode ser chamado mobilizável) 方法
- protegido <T> RunnableFuture <T> newTaskFor (Callable <T> resgatável) {
- retornar nova FutureTask <T> (exigível);
- }
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
- public void executar (comando Runnable) {
- if (comando == null)
- throw new NullPointerException ();
- int c = ctl.get ();
- if (workerCountOf (c) <corePoolSize) {
- if (addWorker (comando, true))
- Retorna;
- c = ctl.get ();
- }
- if (IsRunning (c) && workQueue.offer (comando)) {
- int reverificao = ctl.get ();
- if (! IsRunning (reverificação) && remove (de comando))
- rejeitar (comando);
- else if (workerCountOf (reverificação) == 0)
- addWorker (null, falso);
- }
- else if (! addWorker (comando, false))
- rejeitar (comando);
- }
- 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
- boolean addWorker privada (Runnable firstTask, boolean core) {
- repetir:
- para (;;) {
- int c = ctl.get ();
- int rs = runStateOf (c);
- // Verifique se a fila de esvaziar somente se necessário.
- if (rs> = desligamento &&
- ! (RS == SHUTDOWN &&
- firstTask == null &&
- ! workQueue.isEmpty ()))
- retorna falso;
- para (;;) {
- int wc = workerCountOf (c);
- if (wc> = CAPACIDADE ||
- wc> = (? núcleo corePoolSize: maximumPoolSize))
- retorna falso;
- se (compareAndIncrementWorkerCount (c))
- quebrar de repetição;
- c = ctl.get (); ctl // Re-leitura
- if (runStateOf (c)! = rs)
- continuar de repetição;
- // outra CAS falhou devido a mudança workerCount; repetir loop interno
- }
- }
- booleano workerStarted = false;
- booleano workerAdded = false;
- Trabalhador w = nulo;
- experimentar {
- w = trabalhador novo (firstTask);
- Linha T final = w.thread;
- if (t! = null) {
- definitiva ReentrantLock mainLock = this.mainLock;
- mainLock.lock ();
- experimentar {
- // Verifique novamente enquanto segura bloqueio.
- // De volta em caso de falha ThreadFactory ou se
- // desligado antes bloqueio adquirido.
- int rs = runStateOf (ctl.get ());
- if (rs <SHUTDOWN ||
- (RS == SHUTDOWN && firstTask == nulo)) {
- if (t.isAlive ()) // pré-verificação de que T é inicializável
- throw new IllegalThreadStateException ();
- workers.add (w);
- int = s workers.size ();
- if (s> largestPoolSize)
- largestPoolSize = S;
- workerAdded = true;
- }
- } finalmente {
- mainLock.unlock ();
- }
- if (workerAdded) {
- t.start ();
- workerStarted = true;
- }
- }
- } finalmente {
- if (! workerStarted)
- addWorkerFailed (w);
- }
- voltar workerStarted;
- }
(1) A lógica de decisão é mais complexa, que primeiro olhar para o
- if (rs> = desligamento &&
- ! (RS == SHUTDOWN &&
- firstTask == null &&
- ! workQueue.isEmpty ()))
- 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
- para (;;) {
- int wc = workerCountOf (c);
- if (wc> = CAPACIDADE ||
- wc> = (? núcleo corePoolSize: maximumPoolSize))
- retorna falso;
- se (compareAndIncrementWorkerCount (c))
- quebrar de repetição;
- c = ctl.get (); ctl // Re-leitura
- if (runStateOf (c)! = rs)
- continuar de repetição;
- // outra CAS falhou devido a mudança workerCount; repetir loop interno
- }
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.
- public void run () {
- runWorker (este);
- }
- definitiva runWorker vazio (trabalhador w) {
- Passe em peso = Thread.currentThread ();
- tarefa executável = w.firstTask;
- w.firstTask = nulo;
- w.unlock (); // permitir interrupções
- booleano completedAbruptly = true;
- experimentar {
- while (tarefa! = null || (task = getTask ())! = null) {
- w.lock ();
- // Se a piscina está parando, assegurar fio é interrompido;
- // se não, garantir thread não é interrompido. este
- // exige uma nova verificação em segundo caso de lidar com
- // shutdownNow corrida, enquanto compensação de interrupção
- if ((runStateAtLeast (ctl.get (), STOP) ||
- (Thread.interrupted () &&
- runStateAtLeast (ctl.get (), STOP))) &&
- ! Wt.isInterrupted ())
- wt.interrupt ();
- experimentar {
- BeforeExecute (em peso, tarefa);
- Throwable jogado = null;
- experimentar {
- task.run ();
- }finalmente {
- AfterExecute (tarefa, jogado);
- }
- } finalmente {
- tarefa = nulo;
- w.completedTasks ++;
- w.unlock ();
- }
- }
- completedAbruptly = false;
- } finalmente {
- processWorkerExit (w, completedAbruptly);
- }
- }
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 ()
- privado Runnable getTask () {
- booleano TimedOut = false; // Será que a última poll () fora do tempo?
- para (;;) {
- int c = ctl.get ();
- int rs = runStateOf (c);
- // Verifique se a fila de esvaziar somente se necessário.
- if (rs> = desligamento && (rs> = PARAR || workQueue.isEmpty ())) {
- decrementWorkerCount ();
- return null;
- }
- int wc = workerCountOf (c);
- // Os trabalhadores sujeitos a abate?
- booleano cronometrada = allowCoreThreadTimeOut || wc> corePoolSize;
- if ((wc> maximumPoolSize || (cronometrado && TimedOut))
- && (wc> 1 || workQueue.isEmpty ())) {
- se (compareAndDecrementWorkerCount (c))
- return null;
- continuar;
- }
- experimentar {
- r = Execut�el cronometrado?
- workQueue.poll (KeepAliveTime, TimeUnit.NANOSECONDS):
- workQueue.take ();
- if (r! = null)
- retornar r;
- TimedOut = true;
- } Catch (repetição InterruptedException) {
- TimedOut = false;
- }
- }
- }
getTask é um método para o método de loop infinito, ele primeiro determina o estado atual do pool de threads
- if (rs> = desligamento && (rs> = PARAR || workQueue.isEmpty ())) {
- decrementWorkerCount ();
- return null;
- }
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.
- r = Execut�el cronometrado?
- workQueue.poll (KeepAliveTime, TimeUnit.NANOSECONDS):
- 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)
- Lista pública <Runnable> shutdownNow () {
- List <Execut�eis> tarefas;
- definitiva ReentrantLock mainLock = this.mainLock;
- mainLock.lock ();
- experimentar {
- checkShutdownAccess ();
- // shutDwonNow como STOP, o desligamento como SHUTDOWN
- advanceRunState (STOP); (advanceRunState (shutdown);)
- interruptWorkers ();) (interruptIdleWorkers
- // shutDownNow especial
- tarefas = drainQueue ();
- // desligamento callback especial ScheduledThreadPoolExecutor
- OnShutdown ();
- } finalmente {
- mainLock.unlock ();
- }
- tryTerminate ();
- voltar tarefas;
- }
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
- interruptWorkers private void () {
- definitiva ReentrantLock mainLock = this.mainLock;
- mainLock.lock ();
- experimentar {
- for (Trabalhador w: trabalhadores)
- w.interruptIfStarted ();
- } finalmente {
- mainLock.unlock ();
- }
- }
Obviamente, este é interrompido todos os segmentos (2) o desligamento
- interruptIdleWorkers private void (boolean onlyOne) {
- definitiva ReentrantLock mainLock = this.mainLock;
- mainLock.lock ();
- experimentar {
- for (Trabalhador w: trabalhadores) {
- Rosca t = w.thread;
- if (! t.isInterrupted () && w.tryLock ()) {
- experimentar {
- t.interrupt ();
- } Catch (SecurityException ignorar) {
- } finalmente {
- w.unlock ();
- }
- }
- se (onlyOne)
- pausa;
- }
- } finalmente {
- mainLock.unlock ();
- }
- }
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
- última vazio tryTerminate () {
- para (;;) {
- int c = ctl.get ();
- se (IsRunning (c) ||
- runStateAtLeast (c, arrumar) ||
- (RunStateOf (c) == SHUTDOWN &&! WorkQueue.isEmpty ()))
- Retorna;
- if (workerCountOf (c)! = 0) {// elegível para terminar
- interruptIdleWorkers (apenas_um);
- Retorna;
- }
- definitiva ReentrantLock mainLock = this.mainLock;
- mainLock.lock ();
- experimentar {
- se (ctl.compareAndSet (c, ctlOf (arrumar, 0))) {
- experimentar {
- terminada ();
- } finalmente {
- ctl.set (ctlOf (TERMINADO, 0));
- termination.signalAll ();
- }
- Retorna;
- }
- } finalmente {
- mainLock.unlock ();
- }
- // outra repetição no CAS falhou
- }
- }
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.
- boolean awaitTermination público (longo tempo de espera, a unidade TimeUnit)
- lança InterruptedException {
- longo nanos = unit.toNanos (timeout);
- definitiva ReentrantLock mainLock = this.mainLock;
- mainLock.lock ();
- experimentar {
- para (;;) {
- if (runStateAtLeast (ctl.get (), TERMINADO))
- return true;
- se (nanos <= 0)
- retorna falso;
- nanos = termination.awaitNanos (nanos);
- }
- } finalmente {
- mainLock.unlock ();
- }
- }
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.
- static final int privado de rolamento = -1 << COUNT_BITS;
- SHUTDOWN private static final int = 0 << COUNT_BITS;
- PARAR private static final int = 1 << COUNT_BITS;
- Arrumar private static final int = 2 << COUNT_BITS;
- 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 () 方法 完成