Os tutoriais de Java dizem que a criação de um Thread é cara. Mas por que exatamente é caro? O que exatamente está acontecendo quando um Java Thread é criado que torna sua criação cara? Estou aceitando a afirmação como verdadeira, mas estou interessado apenas na mecânica da criação de threads na JVM.
Sobrecarga do ciclo de vida do encadeamento. A criação e desmontagem de threads não são gratuitas. A sobrecarga real varia entre plataformas, mas a criação do encadeamento leva tempo, introduzindo latência no processamento de solicitações e requer alguma atividade de processamento pela JVM e pelo SO. Se as solicitações forem frequentes e leves, como na maioria dos aplicativos de servidor, a criação de um novo encadeamento para cada solicitação poderá consumir recursos computacionais significativos.
Da simultaneidade Java na prática
Por Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes e Doug Lea
Imprimir ISBN-10: 0-321-34960-1
fonte
Respostas:
A criação do encadeamento Java é cara porque há bastante trabalho envolvido:
Também é caro, no sentido de que o encadeamento amarra recursos enquanto estiver vivo; por exemplo, a pilha de encadeamentos, quaisquer objetos acessíveis a partir da pilha, os descritores de encadeamentos da JVM, os descritores de encadeamentos nativos do SO.
Os custos de todas essas coisas são específicos da plataforma, mas não são baratos em nenhuma plataforma Java que eu já tenha encontrado.
Uma pesquisa no Google me encontrou um antigo benchmark que relata uma taxa de criação de threads de ~ 4000 por segundo em um Sun Java 1.4.1 em um Xeon de dois processadores antigos de 2002, executando o Linux antigo de 2002. Uma plataforma mais moderna dará números melhores ... e não posso comentar sobre a metodologia ... mas pelo menos fornece uma estimativa de quanto a criação de encadeamentos provavelmente será cara .
Os testes comparativos de Peter Lawrey indicam que a criação de encadeamentos é significativamente mais rápida atualmente em termos absolutos, mas não está claro quanto disso se deve a melhorias no Java e / ou no sistema operacional ... ou em velocidades mais altas do processador. Mas seus números ainda indicam uma melhoria de mais de 150 vezes se você usar um pool de threads em vez de criar / iniciar um novo thread a cada vez. (E ele afirma que tudo isso é relativo ...)
(O exemplo acima pressupõe "encadeamentos nativos" em vez de "encadeamentos verdes", mas todas as JVMs modernas usam encadeamentos nativos por motivos de desempenho. Encadeamentos verdes são possivelmente mais baratos de criar, mas você paga por ele em outras áreas.)
Pesquisei um pouco para ver como a pilha de um encadeamento Java realmente é alocada. No caso do OpenJDK 6 no Linux, a pilha de encadeamentos é alocada pela chamada para
pthread_create
criar o encadeamento nativo. (A JVM não passapthread_create
uma pilha pré-alocada.)Em seguida, na
pthread_create
pilha é alocado por uma chamada dammap
seguinte maneira:De acordo com
man mmap
, oMAP_ANONYMOUS
sinalizador faz com que a memória seja inicializada em zero.Portanto, mesmo que não seja essencial que as novas pilhas de encadeamentos Java sejam zeradas (conforme a especificação da JVM), na prática (pelo menos com o OpenJDK 6 no Linux) elas são zeradas.
fonte
malloc()
função, que a JVM pode muito bem usar, se não garantir que a memória alocada é zero-ed (presumivelmente para evitar apenas esses problemas de desempenho).mmap()
chamada sejam copiadas na gravação mapeadas para uma página zero, para que sua inicialização ocorra não dentro demmap()
si mesma, mas quando as páginas são gravadas pela primeira vez e, em seguida, apenas uma página em um tempo. Ou seja, quando o encadeamento inicia a execução, com o custo de custo pelo encadeamento criado, em vez do encadeamento do criador.Outros discutiram de onde vêm os custos da segmentação. Esta resposta cobre por que a criação de um encadeamento não é tão cara em comparação com muitas operações, mas relativamente cara em comparação com as alternativas de execução de tarefas, que são relativamente menos caras.
A alternativa mais óbvia para executar uma tarefa em outro thread é executar a tarefa no mesmo thread. Isso é difícil de entender para aqueles que assumem que mais threads são sempre melhores. A lógica é que, se a sobrecarga de adicionar a tarefa a outro encadeamento for maior que o tempo que você economiza, pode ser mais rápido executar a tarefa no encadeamento atual.
Outra alternativa é usar um pool de threads. Um conjunto de encadeamentos pode ser mais eficiente por dois motivos. 1) reutiliza threads já criados. 2) você pode ajustar / controlar o número de threads para garantir o desempenho ideal.
O programa a seguir imprime ....
Este é um teste para uma tarefa trivial que expõe a sobrecarga de cada opção de segmentação. (Esta tarefa de teste é o tipo de tarefa que é realmente melhor executada no encadeamento atual.)
Como você pode ver, a criação de um novo encadeamento custa apenas ~ 70 µs. Isso pode ser considerado trivial em muitos casos de uso, se não na maioria. Relativamente falando, é mais caro que as alternativas e, em algumas situações, um pool de threads ou não usar threads é uma solução melhor.
fonte
Em teoria, isso depende da JVM. Na prática, todo encadeamento possui uma quantidade relativamente grande de memória da pilha (256 KB por padrão, eu acho). Além disso, os threads são implementados como threads do SO, portanto, criá-los envolve uma chamada do SO, ou seja, uma opção de contexto.
Realize que "caro" em computação é sempre muito relativo. A criação de threads é muito cara em relação à criação da maioria dos objetos, mas não muito cara em relação a uma busca aleatória no disco rígido. Você não precisa evitar criar threads a todo custo, mas criar centenas deles por segundo não é uma jogada inteligente. Na maioria dos casos, se seu design exigir muitos encadeamentos, você deverá usar um conjunto de encadeamentos de tamanho limitado.
fonte
K
= 1024 ek
= 1000.;) en.wikipedia.org/wiki/KibibyteExistem dois tipos de threads:
Threads apropriados : são abstrações em torno dos recursos de encadeamento do sistema operacional subjacente. A criação de threads é, portanto, tão cara quanto a do sistema - sempre há uma sobrecarga.
Threads "verdes" : criados e programados pela JVM, são mais baratos, mas não ocorrem paralelismos adequados. Eles se comportam como encadeamentos, mas são executados no encadeamento da JVM no SO. Eles não são usados com frequência, que eu saiba.
O maior fator que consigo pensar na sobrecarga de criação de threads é o tamanho da pilha que você definiu para os threads. O tamanho da pilha do encadeamento pode ser passado como parâmetro ao executar a VM.
Fora isso, a criação de encadeamentos depende principalmente do sistema operacional e até da implementação da VM.
Agora, deixe-me apontar uma coisa: criar threads é caro se você planeja disparar 2000 threads por segundo, a cada segundo de seu tempo de execução. A JVM não foi projetada para lidar com isso . Se você tiver alguns trabalhadores estáveis que não serão demitidos e mortos repetidamente, relaxe.
fonte
A criação
Threads
requer a alocação de uma quantidade razoável de memória, pois é necessário criar não uma, mas duas novas pilhas (uma para código java e outra para código nativo). O uso de Executores / Pools de Threads pode evitar a sobrecarga, reutilizando threads para várias tarefas do Executor .fonte
Obviamente, o cerne da questão é o que significa 'caro'.
Um encadeamento precisa criar uma pilha e inicializar a pilha com base no método run.
Ele precisa configurar estruturas de status de controle, ou seja, em que estado está executando, aguardando etc.
Provavelmente há muita sincronização em torno da configuração dessas coisas.
fonte