Prefácio
Na programação multithread, não é realista atribuir um thread a cada tarefa, e o consumo aéreo e de recursos da criação de threads são muito altos. Os piscinas de threads surgiram e se tornaram uma ferramenta poderosa para gerenciarmos threads. Através da interface do executor, o Java fornece um método padrão para dissociar o processo de envio de tarefas e executar o processo e usa o Runnable para representar a tarefa.
Em seguida, vamos analisar a implementação da estrutura de threads de threads java threadpoolExecutor.
A análise a seguir é baseada no JDK1.7
vida útil
No ThreadpoolExecutor , os 3 bits superiores de capacidade são usados para representar o estado de corrida, que são:
1. Running: Receba novas tarefas e processe tarefas na fila de tarefas
2.Shutdown: tarefas que não recebem novas tarefas, mas lidam com filas de tarefas
3.Popa: Nenhuma nova tarefa é recebida, nenhuma fila de tarefas é divulgada e todas as tarefas em andamento são interrompidas ao mesmo tempo
4.TIDA: Todas as tarefas foram encerradas, o número de threads do trabalhador é 0. Quando esse estado for alcançado, terminado () será executado.
5. terminado: terminado () foi executado
Diagrama de transição do estado
As classes atômicas são usadas para representar bits estaduais no ThreadpoolExecutor
atomicinteger final privado ctl = new atomicinteger (ctlof (em execução, 0));
Modelo de pool de threads
Parâmetros principais
CorePoolSize: Número mínimo de threads de trabalhadores vivos (se AllowCorethReadTimeout estiver definido, esse valor é 0)
MaximumPoolSize: o número máximo de fios, limitado pela capacidade
KeepAliveTime: O tempo de sobrevivência do fio correspondente, a unidade de tempo é especificada pela TimeUnit
Trabalho: fila de trabalho, armazenando tarefas a serem executadas
RejeitExecutionHandler: Política de rejeição, a capacidade máxima do pool de threads será acionada após o pool de threads estar cheio: os três primeiros bits em capacidade são usados como bits de bandeira, ou seja, a capacidade máxima do fio do trabalhador é (2^29) -1
Quatro modelos
CachedThreadpool: um pool de fios em cache. Se o tamanho atual do pool de threads exceder os requisitos de processamento, o encadeamento ocioso será reciclado. Quando a demanda aumenta, novos threads podem ser adicionados. Não há limite no tamanho do pool de threads.
FILLTHREADPOOL: Um pool de threads de tamanho fixo. Ao enviar uma tarefa, um thread é criado até que o número máximo de pools de threads seja atingido. Neste momento, o tamanho do pool de threads não mudará mais.
Singlethreadpool: um pool de threads de thread único, que possui apenas um tópico de trabalhador para executar tarefas. Ele pode garantir que as tarefas sejam executadas em série na ordem em que estão na fila. Se este thread terminar de forma anormal, um novo thread será criado para executar tarefas.
ScheduledThreadpool: um pool de threads de tamanho fixo e executa tarefas de maneira atrasada ou cronometrada, semelhante ao timer.
Executar a execução da tarefa
Lógica central:
1. O número atual de threads <CorePoolSize, abre diretamente o novo thread Core para executar o addworker de tarefas (comando, true)
2. Número atual de threads> = CorePoolSize, e a tarefa é adicionada com sucesso à fila de trabalho
1). Verifique se o estado atual do pool de threads está em execução
2). Caso contrário, a tarefa é rejeitada
3). Nesse caso, determine se o número atual de threads é 0. Se for 0, adicione um thread do trabalhador.
3. Ligue a tarefa de execução de encadeamento normal (comando, false) e recusar a tarefa se ela não iniciar. A partir da análise acima, podemos resumir os quatro estágios da operação do pool de threads:
1) .PoolSize <CorePoolSize e a fila está vazia. Um novo thread será criado para processar as tarefas enviadas.
2) .PoolSize == CorePoolSize. No momento, a tarefa enviada entra na fila de trabalho. O tópico do trabalhador obtém a execução da tarefa da fila. Neste momento, a fila não está vazia e não cheia.
3) .PoolSize == CorePoolSize e a fila está cheia. Um novo tópico também será criado para processar a tarefa enviada, mas PoolSize <MaxPoolSize
4) .PoolSize == Maxpoolsize e a fila está cheia, a política de rejeição será acionada
Política de rejeição <r /> mencionamos anteriormente que, se uma tarefa não puder ser executada, ela será rejeitada. RejeitEdExecutionHandler é a interface para lidar com tarefas rejeitadas. Aqui estão quatro estratégias de rejeição.
Abortpolicy: Política padrão, encerrar tarefas, arremesso de rejeição rejeitException
CallerNSPolicy: Execute a tarefa atual no tópico do chamador sem jogar exceções
DispardPolicy: descarte a política, descarte diretamente a tarefa e não jogue exceções
Di Scandolderspolicy: abandone a tarefa mais antiga, execute a tarefa atual e não jogue exceções
Trabalhador no pool de threads
Os trabalhadores herdam abstratoqueedsynchronizer e Runnable. O primeiro fornece ao trabalhador a função de bloqueio, e este último executa o método principal de Threads Runworker do Trabalhador (Worker W) (execução da tarefa SNAP da fila de tarefas). As referências do trabalhador são encontradas na coleção dos trabalhadores e são protegidos pela MainLock.
private final reentrantlock mainlock = new reentrantlock ();
Hashset final privado <trabalhador> trabalhadores = novo hashset <worker> ();
função principal runworker
A seguir, a lógica simplificada, observe: a execução de cada thread do trabalhador executa as seguintes funções
Final Void Runworker (trabalhador w) {thread wt = thread.currentThread (); Tarefa executável = w.firstTask; w.firstTask = null; while (tarefa! = null || (tarefa = gettask ())! = null) {w.lock (); antes execute (WT, tarefa); tarefa.run (); após execute (tarefa, jogado); W.Unlock (); } ProcessWorkErexit (w, concluído);} 1. Obtenha a tarefa do getTask ()
2. Bloqueie o trabalhador
3. Execute antes execute (WT, tarefa), que é o método de extensão fornecido pelo ThreadPoolExecutor para subclasses
4. Execute a tarefa. Se o trabalhador configurou a primeira tarefa, a primeira tarefa será executada primeiro e apenas uma vez.
5.
6. Desbloqueie o trabalhador
7. Se a tarefa obtida for nula, feche o trabalhador
Obtenha a tarefa GetTask
A fila de tarefas dentro do pool de threads é uma fila de bloqueio, que é passada durante a construção.
Private Final BlockingQueue <Runnable> WorkQueue;
getTask () recebe a tarefa da fila de tarefas, suporta bloqueio e tempo limite aguardando tarefas. Quatro situações farão com que o nulo seja devolvido e o trabalhador esteja fechado.
1. O número de fios existentes excede o número máximo de threads
2. O pool de threads está no estado de parada
3. O pool de threads está no estado de desligamento e a fila de trabalho está vazia
4. Tempo limite da tarefa de espera de thread e o número de threads excede o número de threads retidos
Lógica do núcleo: cronometrado ou bloqueando a tarefa de espera na fila de bloqueio. A tarefa de espera para que o thread do trabalho do trabalho seja fechado.
Timed = allowCorethReadTimeout || WC> CorePoolSize; Runnable r = cronometrado? WorkQueue.poll (KeepAliveTime, timeUnit.NanosEconds): workqueue.take ();
Esperando por uma tarefa vai tempo em dois casos:
1. Permita que os threads principais aguardem o tempo limite, ou seja, AllowCorethReadTimeout (true)
2. O fio atual é um fio normal, neste momento WC> CorePoolSize
A fila de trabalho usa BlockingQueue, então não a expandirei aqui. Vou escrever uma análise detalhada mais tarde.
Resumir
ThreadpoolExecutor é baseado no modelo de consumidor do produtor. A operação de enviar tarefas é equivalente ao produtor, e o encadeamento das tarefas de execução é equivalente ao consumidor.
Os executores fornecem quatro métodos para construir o modelo de pool de threads com base no ThreadPoolExecutor. Além disso, podemos herdar diretamente o ThreadPoolExecutor e reescrever os métodos de EXECUTE e AfterExecute para personalizar o processo de execução de tarefas do pool de threads.
O uso de filas limitadas ou filas ilimitadas precisa ser considerado de acordo com a situação específica, e o tamanho da fila de trabalho e o número de threads também precisam ser cuidadosamente considerados.
Recomenda -se que a política de rejeição use o callErNSPolicy, que não abandona a tarefa ou joga uma exceção, mas, em vez disso, recua a tarefa do encadeamento do chamador para execução.
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.