Problema com Threads

9 respostas
FabricioPJ

Olá a todos. Aqui, tenho um programa que monitora uma tabela de logs em uma base de dados Oracle. Tudo funcionando perfeitamente. O código da Thread que fica monitorando a base de dados pode ser visto abaixo:

//Thread que fica atualizando a tabela de tempos em tempos Thread monitora = new Thread(new Runnable(){ @Override public void run(){ try{ while(paraThreadMonitora){ proceduresErros.clear(); preencheTabela(); monitoraLinhasTabela(); SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); Date d = new Date(); hora = sdf.format(d); setTitle("Monitorando em tempo real..."); lblMonitorando.setForeground(Color.GREEN); lblMonitorando.setText("Monitorando a cada " + tempoEntreBuscas + " segundos."); lblHoraExecucao.setText("" + hora); lblRegistrosBusca.setText("" + cadsinc.size()); lblUsuario.setText("" + usuario.toUpperCase()); Thread.sleep(tempoEntreBuscas * 1000); //Dorme por X segundos contTotalExecucoesMonitoramento++; } } catch(Exception e){ e.printStackTrace(); } } }, "monitora");

Essa Thread acima é chamada dentro do action de um botão, como pode ser visto abaixo:

try{ paraThreadMonitora = true; paraThreadCronometro = true; cronometro.start(); if(!monitora.isAlive()){ monitora.start(); } } catch(Exception e){ e.printStackTrace(); }

Também existe um botão para interromper esse monitoramento, cuja seu código segue abaixo:

Object[] opcoes = {"SIM", "NÃO"}; int escolha = JOptionPane.showOptionDialog(null, "Deseja interromper o monitoramento?", "Interromper monitoramento.", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, opcoes, opcoes[0]); if(escolha == JOptionPane.YES_OPTION){ paraThreadMonitora = false; paraThreadCronometro = false; cronometro.interrupt(); lblCronometro.setText(""); lblMonitorando.setForeground(Color.RED); lblMonitorando.setText("O monitoramento foi interrompido pelo usuário."); this.setTitle("Monitoramento interrompído"); }

Quando eu interrompo o monitoramento, através do código acima, nenhuma exception ocorre, mas se eu tentar iniciar novamente esse monitoramento, o seguinte erro ocorre:

java.lang.IllegalThreadStateException at java.lang.Thread.start(Thread.java:595) at br.com.Visao.Principal.mnuBuscaHoraActionPerformed(Principal.java:537) at br.com.Visao.Principal.access$1200(Principal.java:24) at br.com.Visao.Principal$10.actionPerformed(Principal.java:440) at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995) at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318) at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387) at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242) at javax.swing.AbstractButton.doClick(AbstractButton.java:357) at javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1225) at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:1266) at java.awt.Component.processMouseEvent(Component.java:6134) at javax.swing.JComponent.processMouseEvent(JComponent.java:3265) at java.awt.Component.processEvent(Component.java:5899) at java.awt.Container.processEvent(Container.java:2023) at java.awt.Component.dispatchEventImpl(Component.java:4501) at java.awt.Container.dispatchEventImpl(Container.java:2081) at java.awt.Component.dispatchEvent(Component.java:4331) at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4301) at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3965) at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3895) at java.awt.Container.dispatchEventImpl(Container.java:2067) at java.awt.Window.dispatchEventImpl(Window.java:2458) at java.awt.Component.dispatchEvent(Component.java:4331) at java.awt.EventQueue.dispatchEvent(EventQueue.java:599) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161) at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

Ou seja, para eu reiniciar o monitoramento, tenho que reiniciar o programa, pois se eu interromper a Thread e inicia-la de novo, gera o erro acima citado.

Onde eu estou errando?

Grato pela atenção.

9 Respostas

E

Não use “interrupt” para interromper uma thread. O indicado é você ficar checando uma flag.

Vini_Fernandes

Cara, desconfio que voce esteja executando o metodo start da sua tread mais de uma vez e isso esta lançando a excecao! Lembre-se que uma thread pode chamar o start uma unica vez, por exemplo:

// seu codigo
Thread minhaThread = new MinhaThread();
minhaThread.start();//aqui tudo bem
//executando outras rotinas
minhaThread.start();//aqui sera lancada outra excecao

Espero ter ajudado!

M

Exato. Assim como você fez na Thread monitora.

Leonardo_Gloria

Exatamente!

Acredito que a exceção esteja sendo gerada por que está se usando start() duas vezes na msm thread!

FabricioPJ

Agradeço a atenção dos colegas. Realmente eu estava “startando” várias vezes a Thread “monitora”. Agora estou usando um booleano para realizar esse controle. Agora o erro não ocorre.
Então coloquei esse código abaixo, no action do botão que inicia o monitoramento, apenas para testes:

if(monitora.isAlive()){ System.out.println("Thread monitora esta viva"); } else{ System.out.println("Thread monitora esta morta"); }

Ele me retorna false, ou seja, a Thread já “morreu”, mas a única coisa que fiz foi setar a variavel booleana “threadMonitora” para false.

Não existe uma maneira de “reviver” essa thread?

Vini_Fernandes

Creio que voce queira algo como Thread.sleep(long); ou Thread.yield(); Veja a documentacao

ViniGodoy

Simples, crie novamente um objeto novo com “new” e depois dê start() nesse novo objeto.

Para iniciar a thread faça:

if (monitora != null)
   return;
monitora = new ThreadMonitora();
monitora.start();

Para parar a thread:

monitora.interrupt(); monitora = null;

ViniGodoy

Não é bem assim. Na verdade, é mais prático usar o interrupt(), já que ele pode tirar a thread de um sleep() ou de um wait().
Entretanto, o alerta fica para que a thread seja programada para isso:

public void run() { try { while (!Thread.isInterrupted()) { //Faz qualquer coisa } } catch (InterruptedException e) { } }

Note que o interrupted exception tira a thread do loop. E que também testamos se o método isInterrupted() é setado para true (pode ocorrer caso o interrupt seja chamado fora de um sleep ou wait). A vantagem dessa abordagem é que a VM chama interrupt() quando você chama um System.exit(0). E isso permite encerrar essas threads graciosamente.

FabricioPJ

Opa, obrigado a todos.

Irei testas vossas soluções e depois posto o resultado.

Criado 2 de outubro de 2009
Ultima resposta 5 de out. de 2009
Respostas 9
Participantes 6