Você só pode chamar o wait em blocos sincronizados. Se você só quer dar uma pausa, use o Thread.sleep no lugar.
S
spiderman
Eu estou precisando fazer dois acordadores para esta thread UpStatus. Eu tenho uma thread externa que deverá acordar a UpStatus e além disso se esta externa não conseguir acordar a UpStatus deve acordar sozinha após 5 ou 10s.
Só que não estou conseguindo resolver este problema. Pode me auxiliar?
ViniGodoy
Primeiro de tudo. Threads são uma coisa, objetos são outra. Até que você entenda bem esse conceito, fica mesmo difícil modelar o seu problema.
Tente não fazer suas classes estenderem thread, e organize bem o seu negócio.
Outra coisa, a classe Thread representa só um disparador de thread. Ser filho de thread, não é uma thread. Uma thread pode percorrer vários objetos, bem diferentes do qual ela foi disparada.
Agora que isso ficou claro, vamos ao seu problema. Antes de eu te ajudar, me diga, o que seu código tem que fazer? Qual problema você está tentando resolver?
S
spiderman
o Problemas é este, simples mas não estou entendendo.
packageacordandoThreadExterna;publicclassProdutorTrabalho{Trabalhadorw;intvalor;intid=1;publicstaticvoidmain(String[]args){ProdutorTrabalhoprod=newProdutorTrabalho();prod.inicializa();}publicvoidinicializa(){for(inti=0;i<5;i++){this.w=newTrabalhador(this.id++,this);this.w.start();this.produz();}}publicvoidproduz(){for(inti=0;i<10;i++){valor=5+(int)(Math.random()*40);this.w.recebe(valor);}}publicvoidrecebeStatus(intt,intstatus){System.out.println("Recebi Status do Trabalhador: "+t+" com tamanho da fila: "+status);}}
packageacordandoThreadExterna;importjava.util.concurrent.BlockingQueue;importjava.util.concurrent.LinkedBlockingQueue;publicclassTrabalhadorextendsThread{ProdutorTrabalhoger;UpStatuscontrol;BlockingQueue<Integer>work;intvalor;intid;publicTrabalhador(intid,ProdutorTrabalhoger){this.id=id;this.ger=ger;this.control=newUpStatus(this);this.control.start();this.work=newLinkedBlockingQueue<Integer>();}publicvoidrun(){try{this.valor=this.work.take();this.fibo(valor);this.atualiza();}catch(InterruptedExceptione){// TODO Auto-generated catch blocke.printStackTrace();}}publicvoidatualiza(){this.ger.recebeStatus(this.getID(),this.work.size());}publicvoidrecebe(intvalor){try{this.work.put(valor);}catch(InterruptedExceptione){// TODO Auto-generated catch blocke.printStackTrace();}}publicintfibo(intn){if(n<=1)returnn;returnfibo(n-1)+fibo(n-2);}publicvoidsetID(intid){this.id=id;}publicintgetID(){returnthis.id;}}
Possui uma Classe ProduzTrabalho que ira produzir um numero qualquer para a classe Trabalhador, esta calcula o fibonacci deste numero. Alem disso esta classe deve enviar seu status para a classe ProduzTrabalho, para isso criei uma classe Thread UpStatus que é iniciada quando um Trabalhador é instanciado, esta UpStatus deve ser acordada em dois momentos, logo após que o Trabalhador acaba de calcular o fibonacci e a cada 5s.
O problema é que esta ocorrendo
java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at core.UpdateStatusWorker.run(UpdateStatusWorker.java:17)
E eu nao estou descobrindo porque disso.
ViniGodoy
Ok. Então vc tem duas classes. A ProduzTrabalho, que é a produtora, e a Trabalhador, que é a consumidora.
Que status o trabalhor deve mandar para a classe produtora? E para que? Seria para dizer que ela está livre?
É isso mesmo. O status vai a informação do tamanho da fila. Eu preciso fazer um teste ainda no metodo recebeStatus, que verifica se esta com pouco trabalho ou nao, ou seja, se a fila dele for menor que 3 tenho que produzir mais para este trabalhador. Mas isso pode ser em um segundo momento, pois como vou fazer isso se o envio de status não está funcionando direito.
ViniGodoy
Veja como fica:
ProdutorTrabalho.java
importjava.util.Random;publicclassProdutorTrabalho{privateTrabalhadortrabalhador;privateRandomrandom=newRandom();publicProdutorTrabalho(Trabalhadortrabalhador){this.trabalhador=trabalhador;// Disparamos a thread produtoraThreadprodutor=newThread(newRunnable(){publicvoidrun(){produzirTrabalho();}});produtor.setName("Produtor");produtor.start();}/** * Método do produtor que recebe um status enviado pelo trabalhador. Isso faz com que o produtor gere trabalho * imediatamente caso a fila seja < 3. */publicsynchronizedvoidreceberStatus(inttamFila){System.out.print("Requisiçãodetrabalho");if(tamFila<3){System.out.println("aceita.");// Esse notify irá acordar o wait do método produzTrabalho.notifyAll();}elseSystem.out.println("negada.Jáhámuitotrabalhonafila.");}/** * Gera um novo trabalho a cada 5 segundos, ou quando uma requisição for feita ao receber status. */privatesynchronizedvoidproduzirTrabalho(){try{while(!Thread.interrupted()){intnr=random.nextInt(40)+10;System.out.println("Trabalhoproduzido:"+nr);trabalhador.receberTrabalho(nr);// Aguarda 5s. O notifyAll() também libera o wait.wait(5000);}}catch(InterruptedExceptione){}}}
Trabalhador.java
importjava.util.concurrent.BlockingDeque;importjava.util.concurrent.LinkedBlockingDeque;publicclassTrabalhador{privateBlockingDeque<Integer>trabalhos=newLinkedBlockingDeque<Integer>();privateProdutorTrabalhoprodutor;publicvoiddefinirProdutor(ProdutorTrabalhoprodutor){if(this.produtor!=null)return;this.produtor=produtor;Threadthread=newThread(newRunnable(){@Overridepublicvoidrun(){trabalhar();}});thread.setName("Consumidor");thread.start();}/** Simplesmente insere um trabalho na fila. * O método offer avisa o método take(), que desbloqueia a thread. */publicvoidreceberTrabalho(inttrabalho){trabalhos.offer(trabalho);}publicvoidtrabalhar(){try{System.out.println("Aguardandotrabalho.");while(true){// Aguardamos até que haja trabalho. //O take() bloqueia a thread caso a fila esteja vazia.Integertrabalho=trabalhos.take();//Trabalhamostrabalhar(trabalho);//Avisamos o produtor que concluímos.produtor.receberStatus(trabalhos.size());}}catch(InterruptedExceptione){}}privatevoidtrabalhar(Integertrabalho){System.out.println("TrabalhandonoFibonacci("+trabalho+")...");System.out.println("Resultado:Fibonacci("+trabalho+")="+fibo(trabalho));}privatelongfibo(intn){if(n<=1)returnn;returnfibo(n-1)+fibo(n-2);}}
Só um detalhe. Threads e sincronização está bem longe de ser um assunto de Java Básico. Por isso vou mover seu tópico para Java Avançado.
S
spiderman
ahhh estou entendendo. Mas mais uma dúvida, no produtor você utiliza synchronized nos metodos, está sendo utilizado somente pelo motivo de que você está utilizando o wait e notify, correto? Caso tivesse mais um trabalhador, os métodos no trabalhador não deveriam ter o synchronized?
VLW
ViniGodoy
Não é necessário sincronizar os métodos do consumidor pois a sincronização é fornecida pela LinkedBlockingQueue.
No caso do produtor, sim, usamos sincronização por causa do wait e do notify.