Tutorial Avançado sobre Threads

15 respostas
saoj

A idéia inicial era tentar escrever um livro sobre aplicações colaborativas em Java, mas como empaquei no primeiro capítulo e estou sem previsões de acabar o restante, estou disponibilizando para a comunidade o que eu fiz até agora.

Trata-se de um tutorial avançado sobre threads. Quem ler, por favor me diga se ficou bom, pontos que devem ser melhorados, etc.

http://www.smartjava.com.br/threads2.html

15 Respostas

louds

Seu tutorial é, digamos assim, um pouquinho perverso com as boas práticas de programação concorrente em java.

Vamos lá…
No exemplo de como matar 1 thread você usa uma variavel bThread, que não é,nem volátil e nem tem seu acesso sincronizado, porêm a lê e modifica de forma concorrente. Isso é errado, muito errado. Fora que ela é inútil, o melhor seria executar “while(!isInterrupted())”, assim a arruma a semântica e fica mais claro sua intensão, pq para mim “bThread” é nome da Thread que vem depois da “aThread”.

Outra coisa é o fato da VM do java assumir somente a existencia de um sistema preemptivo, se o SO hospedeiro não o for, a JVM deve emular tal condição.
O uso indiscriminado de yield() vai reduzir o throughtput do sistema sem ganhos significativos em interatividade na execução das threads.
Seu uso só é justificavel na construção de algumas poucas primitivas para concorrencia quando dar uma dica para o scheduler resulta em ganhos de performance, por exemplo, uma thread em iminencia de ficar bloqueada sabendo que a “dona do passe” precisa de muito pouca cpu para liberar e não tem prioridade inferior.

Aproveitando o assunto, o sistema cooperativo mais rescente que eu tenho notícia é o windows 3.11, os unixes são todos preemptivos desde algum momento da década de 80. Sistemas cooperativos são possiveis de serem encontrados em dispositivos embarcados e ainda assim não importa pq a JVM emula o comportamento preemptivo.

Green Threads não são sempre cooperativas. Elas apenas fazem userland scheduling. Green Threads podem escalar para mais de 1 processador.
A IBM desenvolveu uma época o NPTL, que substituiria a biblioteca de threading do linux usando um modelo híbrido com LWP (kernel thread) e green threads permitindo alta escalabilidade em sistemas SMP.

Acho que vc confundiu Green Threads com os fibers do windows, que é uma API para threading cooperativo.

Fora isso você esqueceu de falar sobre o modelo de monitors que o java utiliza, variaveis voláteis e os seus por quês, a diferença de notify() e notifyAll().

saoj

:shock: Vc é bom para avaliar tutoriais !!! :shock:

Meu direito a réplica:

Estou sem meu dicionário aqui! O que é pervenso? Isso é um xingamento ou uma maneira carinhosa de falar que vc não concordou com nada?

Seguindo o seu estilo de análise de tutorais, while(!isInterrupted()) é errado, aliás, muito errado. Faça isso e aí sim vc vai ter problemas. Se vc tivesse lido a documentaçao, ou programado mais com isso, vc saberia que quando vc interrompe um thread que está dormindo com interrupt(), então um isInterrupted() vai te retornar false e não true como vc está pensando. Vc foi pervenso com as boas práticas de programação concorrente em Java. :evil: :evil: :evil:

Calma !!! Antes de gritar que isso é totalmente errado e que eu mereço morrer, veja que o volatile só vai te trazer dores de cabeça QUANDO VC TEM PARALELISMO, OU SEJA, mais de dois processadores executando o seu programa. Se o seu programa vai executar numa máquina com apenas um microprocessador, o VOLATILE É TOTALMENTE DESNECESSÁRIO. Se vc não concorda então me mostra um programinha que eu possa rodar numa máquina com um processador e que eu vou me ferrar porque estou sem volatile.

Mas vc levantou um excelente ponto, que merece uma explicação no meu tutorial. Realmente, academicamente falando e para ficar tranquilo num ambiente com paralelismo, eu deveria ter definido bThread como volatile. Me perdoe. Desculpe tb pelo nome bThread. É um nome infeliz mesmo.

Reeitero que todos meus servidores Java que estão em produção NÃO ESTÃO FAZENDO USO DE VOLATILE e funcionam perfeitamente !!! Talvez devido ao fato de que eu NÃO ESTAR UTILIZANDO PARALELISMO !!!

Cara, não sei se toda essa teoria que vc falou é certa ou errada. O que posso te garantir é que em Solaris vc tem o conceito de LWP e que os seus threads dentro desses LWP são cooperativos !!! Então se vc não coloca um yield vc dança bonito e os seus threads vão starvar. Vc nunca ouviu reclamações de pessoas que rodaram um programinha multi-threaded em Unix e se ferraram por causa disso ??? Eu já ouvi várias histórias !!!

Mas aí não é mais green threads !!! É a implementaçao da IBM e nao da VM.

Realmente menosprezei volatile e deixei brecha pra vc me tacar pedra. Se vc escreveu um tutorial sobre threads em algum lugar, então coloque o link aqui para as pessoas poderem entender melhor sobre esse conceito. Agora revise bem a coisa, pois vou olhar cada ponto-e-vírgula dele… :evil:

Quanto ao notify e o notifyAll eu falei sim:

Obrigado pela sutileza de suas críticas. Adorei !!! :?

Daniel_Quirino_Olive

Explica para mim: se você faz uma aplicação multi-thread mas não consegue usar em ambientes paralelos com ganhos reais de desempenho, pra que diabos você vai escrevê-la assim? Você tem que escrever uma aplicação multi-thread pensando que ela pode ter um desempenho melhorado caso eu a implante em uma máquina multi-processada. Logo, não importa se você vai ou não usar máquinas paralelas, você precisa usar volatile para indicar que uma variável pode ser alterada por threads.
Sugestão: capítulo 7 do Effective Java :wink:

saoj

Tem razão Daniel !!! Foi bobeira minha ficar fazendo programação multithreaded com Java em máquinas monoprocessadas. Uma total perda de tempo !!! Deve ser por isso que só agora threads estão ganhando mais espaço no mundo java, pois agora as máquinas multiprocessadas estão mais em conta e há mais delas por aí.

hehhe… eu prefiro o Learning Java da O’Reilly…

Agora só falta o CV entrar me detonando… hehehehe

:stuck_out_tongue: :stuck_out_tongue: :stuck_out_tongue: :stuck_out_tongue:

louds

Vejamos, errar é humano, eu queria dizer “perverso” no primeiro parágrafo.

Do uso de isInterrupted(), essa é a forma correta de sinalizar e verificar se uma thread deve ser finalizada. Isso segundo o Doug Lea, olhe os fontes do dl.u.c. para ver bons exemplos.
Se uma thread estiver em espera e for interrompida, ela vai tratar a InterruptedException e parar, mas e se ela estiver fazendo busy waiting? Como suportamente eu devo interromper de forma simples nesses dois casos? Pense um pouco e vai ser que é o caso de usar isInterrupted() :wink:

Programar usando multiplas threads e não pensar no código executando em múltiplos processadores é a mesma coisa que dirigir pretendendo sempre estar em ruas vazias.

Voce pesquisou mesmo esse fato dos containers não usarem volatile? Os frameworks de concorrencia que eu estudei os fontes todos usando variaveis volatile em muitos pontos.

Se você está usando mais de uma thread está usando paralelismo :wink: O uso sano de variaveis voláteis é importante quando se lida com JVMs com JITers optimizadores e multiplas cpus com caches não coerentes, ou todos sistemas SMP atuais.

Não vou discutir sobre SOs, apenas que a maquina virtual que roda sob o java é sempre preemptiva. Teu tutorial não é para threading usando “fibers” em Solaris na última vez que eu verifiquei.

O uso de yield da forma que voce sugere é uma idéia tão ruim que o pessoal do OpenOffice tomou na cabeça com o kernel 2.6 do linux, o qual implementa a semântica mais aceita, que é de diminuir a prioridade dinâmica do LWP dando yield antes de chamar o escalonador.

Fora isso eu te desafio a provar que usando yield() existe como aumentar o thoughtput de um sistema, ou evitar que ele diminua.

Por sinal, qual a sua definição formal de uma green thread? Acho que voce está falando de uma coisa bem diferente que eu.

Quanto ao notify e notifyAll você não disse qual a utilidade de cada um. Quem lê o seu texto sai entendendo que notifyAll() é a versão lenta do notify(). Onde está o exemplo que justifique o uso do notifyAll()?

Luca

Olá

Sérgio, achei ótimo você submeter seu tutorial a críticas. Mas achei péssima sua reação a elas. Quem dera eu tivesse o louds para examinar e criticar meu trabalho. Então devido a sua reação só farei 2 comentários:

  1. Retire o termo avançado do título. Nem o Doug Lea, Jack Shirazi e o Paul Hyde tiveram esta ousadia.

  2. Tenho uns 70 livros de Java. O Effective Java certamente é um dos 5 melhores. Só o capítulo 4 já vale o que paguei por ele. Mesmo que não soubesse que iria levar pedrada se criticasse, só o fato de você não gostar dele já me deixa sem vontade de examinar mais a fundo seu tutorial.

[]s
Luca

saoj

Fala louds !!! Acho que já deu para a gente se divertir. Concordo com algumas coisas que vc falou, só não concordo com a maneira que foi dita. Fazendo uma meia-culpa, acho que tb me precipitei quando coloquei o meu tutorial com o título avançado.

Thread faz parte do core da linguagem Java e é fundamental para diversas coisas estando vc ou não num ambiente multiprocessado. É claro que eu cometi um erro ao ignorar os ambientes multiprocessados e não declarar o meu boolean como volatile, mas como vc mesmo disse, errar é humano.

Se eu não me engano, as primeiras VMs ignoravam essa keyword volatile, e houve uma grande dúvida inicial se uma associação em Java era (a = b) era atômica ou não. Algumas pessoas mais atentas ressaltaram que alguns primitivos (long e double) tem 64 bits e precisaria de dois ciclos de CPU para se completar em processadores de 32-bits, logo pelo menos no nível do microprocessador não tinha como ser atomica. Acho que o volatile caiu como uma luva para solucionar essa questão.

No meu Unix box aqui eu posso fazer java -green e vou ter um monte de threads rodando cooperativamente e não preemptivamente e nem em paralelo. Ambiente cooperativos são bem mais performáticos que os preemptivos, pois não há um switch no contexto todo, apenas um branch no código de máquina.

Nunca falei que yield era melhor, apesar de achá-lo bem barato. O fato é que sem yield não há como trabalhar com threads em sistemas cooperativos. Rode os seus programas sem yield com java -green e vc vai entender o que eu estou falando!

Quem precisava definir issa era Sun. Como a coisa ficou vaga, na minha cabeça são threads que rodam dentro da JVM, até onde eu sabia num ambiente cooperativo, sem utilizar os recursos de threading do próprio OS. Daí a idéia de que green threads nunca poderiam rodar em processadores diferentes, pois a VM (não sei porque) ficava (ou ainda fica) atrelada a um único processador sempre.

Tem razão! Eu poderia explicar melhor isso. Vou pesquisar mais sobre isso e melhorarar o tutorial.

saoj

Realmente viajei! Antes de mesmo de vc falar isso eu já tinha me tocado que avançado ficou um pouco pesado. Eu queria passar a idéia de “além do básico”.

Eu pensei que ele estava me zoando, me sugerindo algum livro for dummies, mas agora percebo que ele estava falando do Effective Java do Joshua Block, o cara que fez a API Collections, não é esse? Li esse livro em 2001 e gostei muito tb. Vou le-lo novamente agora.

Já percebi em outras discussões que o louds manja muito de vários assunto, e exatamente por isso ele não precisa avacalhar, mesmo que eu tenha sido infeliz de ter colocado o título do meu tutorial como avançado. Tb sei avacalhar !!! hehehe

Bom… peço desculpas pelo título infeliz…

cv1

E o que nao me pedem sorrindo que eu nao faco com cara de bosta? :mrgreen:

Nao vou nem criticar o artigo - isso ja foi feito muito bem pelo louds e pelo dqo. Mas, cara, a sua reacao me assustou, o que, alias, nao acontece pela primeira vez. Se voce pediu criticas ao seu trabalho, entao - advinha soh! - voce vai levar criticas ao seu trabalho. Boas, ruins, injustas, invalidas, ou melhores que o trabalho em si. Sao criticas. Se alguem teve o trabalho de ler, avaliar, e escrever a critica, tambem em publico, e dizer “nao gostei, e aqui estao os porques”, a sua OBRIGACAO eh prestar bem atencao ao que esta sendo dito…

Hmm, peguei pesado. Bom, agora ja foi. Desculpe pelo sermao :wink:

P

Eu vejo por um lado positivo este bla-bla-bla todo:

Não prevaleceu a opnião de um, havendo o desenrolar da discussão.
Isto nos possibilita ver o assunto por vários ângulos, experiências e idéias.

Que bom seria um tutorial escrito a 6, 8 ou 10 mãos (cooperativamente, preempetivamente, ou não !). :lol:

Imagina vc ter o super-hyper-tutorial sobre Threads, reunindo as melhores práticas, pegadinhas, bugs nas implementações,etc. :smiley:

Isto seria um material MUITO VALIOSO, visto que não há como ignorar um assunto tão importante como Threads.

Por isto, discritamente deixo aqui minha sugestão para aqueles que manjam e não manjam de Threads, de que se reunissem na forma de um Wiki ou algo assim, para criar um belo e importante material.

Bem, esta é a minha opnião.

set pedrada = on

caiofilipini

“boone”:
Que bom seria um tutorial escrito a 6, 8 ou 10 mãos (cooperativamente, preempetivamente, ou não !). :lol:

Imagina vc ter o super-hyper-tutorial sobre Threads, reunindo as melhores práticas, pegadinhas, bugs nas implementações,etc. :smiley:

Isto seria um material MUITO VALIOSO, visto que não há como ignorar um assunto tão importante como Threads.

Cara, ótima idéia!!! Wiki Thread Tutorial! :lol:
Bem que a galera podia fazer isso… :wink:

[]'s

urubatan

bahh, acabei de descobrir que metade do que eu sabia sobre Threads não estava tão certo quanto eu pensava :smiley:

valeu pela aula galera :smiley:

saoj

Até que vc foi bem mais benevolente que os outros membros da diretoria ! :smiley:

O bom senso e a humildade (mais sobre isso aqui) ditam que quando vc for criticar o trabalho dos outros, pegue leve. Não use eufemismos nem ironias, do tipo: errado, muito errado, perverso com as boas práticas, além do mais, etc e tal.

Fico imaginando se fosse o inverso, ou seja, se eu fosse criticar desse jeito um post do CV, louds ou dqo. Achei sacanagem menosprezar o tutorial. Uma pessoa, assustada com a repressão, me mandou um email falando que gostou muito do tutorial. Depois dessa discussão toda, acho que ninguém vai ter coragem de dar sua opinião isenta em público.

Acho ótimo !!! Se juntar as experiências da galera aqui teríamos um tutorial pós-avançado sobre Java Threads. Como o louds sugeriu, alguém poderia começar falando mais sobre as diferenças de notifyAll e notify. Confesso que sei apenas o que eu falei no tutorial, ou seja, que notifyAll acorda todos os threads enquanto notify acorda um só, e que me parece que na maioria dos casos, notify é melhor que notifyAll. Qual a vantagem de acordar todos os threads se temos apenas um lock ??? Está aberto para quem quiser opinar…

Para finalizar:

isInterrupted() é nativo, logo como eu sei se o boolean interno que ele usa é volatile ou não ??? Clique aqui para ver o que o mestre google tem a dizer sobre isso. Parece que já teve bug na VM exatamente aí.

Como o Luca sugeriu, fui olhar o livro Effective Java, capítulo 9 e não 7, e lá ele tb fala sobre como parar um thread. E ele tb usa uma variável boolean para testar o while loop, e ele tb fala que é importante declarar a variável como volatile, e ele tb fara que isso só será um problema em máquinas multiprocessadas.

P

“caiofilipini”:
Cara, ótima idéia!!! Wiki Thread Tutorial! :lol:
Bem que a galera podia fazer isso… :wink:

[]'s

Eu dei a idéia do GUJ Wiki, por acreditar que seria uma forma democrática do pessoal colaborar com o conteúdo e esta massa de conhecimento crescer e ser facilmente administrada.

Eu por exemplo, se fosse para opinar sobre o assunto na parte do J2SE, eu não teria nada para colaborar, mas em se tratando de J2ME quem sabe ? Sei pouco, mas com o “pouco” de cada um, é que temos um “muito”.

Daniel_Quirino_Olive

Opa, eu não menosprezei nada. Acredito que o louds também não. Só questionei a validade de um programa multi-thread que não se beneficia de arquiteturas multi-processadas. Só isso.
Ahhh, sobre o capítulo do EJ indicado, foi mal pelo engano :frowning:

Criado 28 de setembro de 2004
Ultima resposta 29 de set. de 2004
Respostas 15
Participantes 8