O pool de threads é, na verdade, uma implementação da tecnologia de pooling. A ideia central da tecnologia de pooling é realizar a reutilização de recursos e evitar a sobrecarga de desempenho causada pela criação e destruição repetida de recursos. O pool de threads pode gerenciar vários threads para que os threads não sejam destruídos após a conclusão da tarefa, mas continuem a processar tarefas que foram enviadas por outros threads.
Benefícios de usar o pool de threads
Reduza o consumo de recursos. Reduza o custo de criação e destruição de threads reutilizando threads criados.
Melhore a velocidade de resposta. Quando uma tarefa chega, ela pode ser executada imediatamente, sem esperar a criação do thread.
Melhore a capacidade de gerenciamento de threads. Threads são recursos escassos. Se forem criados sem restrições, eles não apenas consumirão recursos do sistema, mas também reduzirão a estabilidade do sistema. O pool de threads pode ser usado para alocação, ajuste e monitoramento unificados.
Parâmetros de construção
corePoolSize: usado para trabalhar no pool de threadsNúmero de threads principais。
tamanho máximo da piscina:Número máximo de threads , o número máximo de encadeamentos que podem ser criados pelo conjunto de encadeamentos. Quando o número de threads no pool de threads atingir corePoolSize, se a fila de tarefas estiver cheia e novas tarefas precisarem ser processadas, o pool de threads criará novos threads (mas o número total não excede maxPoolSize) para processar essas tarefas. (Isso equivale a quando a área de fila está cheia, os threads subsequentes podem pular diretamente para a fila.) Se o número de tarefas exceder maxPoolSize e a fila de tarefas estiver cheia, o conjunto de threads processará essas tarefas não executáveis de acordo com a política de rejeição.
keepAliveTime: O tempo de sobrevivência de threads criados após exceder corePoolSize ou todos os threadsTempo máximo de sobrevivência, dependendo da configuração.
unidade:keepAliveTimeunidade de tempo。
fila de trabalho:fila de tarefas , é uma fila de bloqueio. Quando o número de threads atingir o número de threads principais, a tarefa será armazenada na fila de bloqueio. Implementações comuns: classes de implementação da interface BlockingQueue, como ArrayBlockingQueue, LinkedBlockingQueue, etc.
threadFactory: usado para criar threads dentro do pool de threadsfábrica。
manipulador:Política de negação;Quando a fila estiver cheia e o número de threads atingir o número máximo de threads, este método será chamado para processar a tarefa.
Como definir parâmetros
1. Determine o número de threads principais (corePoolSize)
Tarefas com uso intensivo de CPU: Para tarefas com uso intensivo de CPU, é comum definir o número de threads de núcleo entre 1 e 2 vezes o número de núcleos de CPU. Isso garante a utilização total dos recursos da CPU, evitando trocas excessivas de contexto.
Tarefas com uso intensivo de IO: Para tarefas com uso intensivo de IO, como os threads não ocupam a CPU ao aguardar operações de IO, mais threads principais podem ser definidos. De modo geral, o número de threads principais pode ser definido para mais de 2 vezes o número de núcleos da CPU, para que mais tarefas possam ser processadas enquanto aguarda o IO.
Tarefas mistas: se seu aplicativo contiver tarefas com uso intensivo de CPU e de E/S, será necessário equilibrar as configurações para o número de threads principais com base na situação específica.
2. Determine o número máximo de threads (maximumPoolSize)
Ambientes com recursos limitados: Em ambientes com recursos limitados (como sistemas incorporados ou servidores em nuvem), o número máximo de threads precisa ser limitado para evitar que muitos threads ocupem recursos.
Sistema de alta simultaneidade: Para sistemas que precisam lidar com um grande número de solicitações simultâneas, o número máximo de threads pode ser aumentado adequadamente para melhorar as capacidades de processamento simultâneo do sistema. No entanto, a configuração do número máximo de threads deve ser considerada de forma abrangente com base na capacidade de carga e nas condições de recursos do sistema.
3. Defina o tempo ocioso do thread (keepAliveTime)
Aplicativos com uso intensivo de CPU: Para aplicativos com uso intensivo de CPU, geralmente você pode definir o tempo ocioso do thread para um valor mais curto porque os recursos da CPU são muito preciosos e você não deseja que muitos threads ociosos ocupem recursos. Em alguns casos, pode até ser definido como 0, indicando que threads não essenciais não são retidos.
Aplicativos com uso intensivo de IO: Para aplicativos com uso intensivo de IO, como os threads não ocupam recursos da CPU ao aguardar operações de IO, o tempo ocioso do thread pode ser definido para um valor mais longo (como mais de 1 minuto) para evitar inicialização e destruição frequentes do thread . a sobrecarga de desempenho causada.
4. Selecione a fila de tarefas (workQueue)
fila limitada : usar uma fila limitada pode limitar o tempo de espera das tarefas na fila e evitar estouro de memória devido a muitas tarefas. No entanto, se o comprimento da fila for muito pequeno, as tarefas poderão ser rejeitadas. (Geralmente escolha fila limitada)
Fila ilimitada: usar uma fila ilimitada pode armazenar em cache todas as tarefas tanto quanto possível, mas você precisa prestar atenção aos problemas de consumo de memória. Se uma fila ilimitada for usada, o parâmetro número máximo de threads do conjunto de encadeamentos poderá se tornar inválido porque o conjunto de encadeamentos não tenta criar novos encadeamentos para processar tarefas na fila.
5. Configurar fábrica de threads (threadFactory)
A fábrica de threads é usada para criar novos threads. Ao personalizar a fábrica de threads, você pode definir a prioridade do thread, o status do thread daemon e outros atributos, e também pode definir um nome significativo para o thread para facilitar o diagnóstico de problemas na JVM.
6. Configure a política de rejeição (manipulador)
Quando o pool de threads não consegue processar novas tarefas (ou seja, o número de threads atingiu o máximoPoolSize e a fila de tarefas está cheia), uma política de rejeição precisa ser configurada para lidar com essas tarefas não executáveis.Estratégias comuns de rejeição incluemLançar uma exceção diretamente、Use o thread do chamador para executar a tarefa、Ignore novas tarefas e descarte as tarefas mais antigas da fila espere. Você também pode personalizar a política de rejeição conforme necessário.