Para que serve um ThreadPoolExecutor ? [PT]
As duas principais questões que muitos podem ter são:
Para que serve?
Preciso de utilizar um no meu projecto?
Um ThreadPoolExecutor é uma classe Java que conceptualmente serve, essencialmente, para gerir por nós, de forma muito eficiente, um conjunto de Threads! Conceptualmente, porque, se mal configurado pode ter um efeito deficiente.
Agora, em termos práticos, esta classe serve para executar tarefas que consistem em classes que implementem a interface Runnable, que possa ser executada.
Se notarem, de forma similar, uma Thread pode receber no seu construtor uma classe que implemente uma interface Runnable também!
Internamente o ThreadPoolExecutor tem um numero para a quantidade do núcleo e um para a quantidade máxima de Threads activas, o tempo que uma Thread pode permanecer inactiva, uma fila para armazenar as tarefas e uma classe que cria as Threads a partir da fila de tarefas!
Um ThreadPoolExecutor é normalmente utilizado em aplicações que seja necessária a capacidade de executar em simultâneo varias tarefas em detrimento da prioridade das mesmas.
Um bom exemplo disso pode ser um servidor web, pois existem vários pedidos concorrentes, sem uma prioridade estabelecida, mas que no entanto todos eles têm de ser atendidos.
Então, se o projecto consiste em um servidor ou outra aplicação em que se exija executar concorrentemente varias tarefas, utilizar um ThreadPoolExecutor é quase obrigatorio.
Para alem de gerir todas as tarefas, é também possível configurar de forma a adquar ao sistema alvo, podendo fazer funcionar em a favor do sistema ou da aplicação.
O funcionamento de um ThreadPoolExecutor não é muito complicado de perceber. Inicialmente existe um numero definido de Threads concorrentes no núcleo, ou seja, quando mandamos executar uma tarefa é criada uma nova Thread até atingir esse mesmo numero. Se o núcleo estiver preenchido, mas o numero máximo de Threads permitir, são criadas Threads extra para auxiliar. Assim que uma Thread extra se torne inactiva, entra em funcionamento um temporizador que dispara mal o tempo máximo de inactividade seja atingido e as mesmas são libertadas, no entanto, as Threads do núcleo, mesmo que estejam inactivas, nunca são libertadas. Consequentemente, novas tarefas em espera para serem executadas são enviadas para a primeira Thread inactiva, seja do núcleo, seja uma extra.
Com este procedimento é possivel manter um numero de recursos constantemente alocado à execução de tarefas, sem comprometer o funcionamento da aplicação.
O ThreadPoolExecutor possui uma fila interna em que podemos inclusive definir o tipo de armazenamento, se queremos objectos ligados, armazenamento vectorial... etc... Podemos também desenvolver o nosso próprio sistema de armazenamento desde que implemente uma fila.
Todas as Threads são criadas por um objecto especifico para criar Threads a partir das tarefas, por isso também as Threads criadas podem ser especificas para a nossa aplicação.
Quando bem configurado um ThreadPoolExecutor aumenta a fiabilidade, pois temos a certeza que as tarefas vão ser executadas eventualmente e que os recursos atribuídos à aplicação nunca vão oscilar entre níveis muito diferentes dos esperados, tornando a aplicação mais estável e evitando pedir novas Threads desnecessariamente.
A próxima publicação será uma explicação pratica de como configurar um ThreadPoolExecutor.