[RESOLVIDO] Thread + JFileChooser : trava

4 respostas
RenataFA

Bom dia pessoal,

Estou com um probleminha chato.

Tenho um método que tem que retornar um boolean. Dentro desse método eu faço poucas coisas:
- chamo uma thread que vai rodar o processamento e armazenar em uma variável caso dê algum erro
- retornar, de acordo com o conteúdo dessa variável, o boolean que preciso

De forma simples, algo assim:

public boolean importar(/*meus parametros estao aqui*/){
		
		ThreadImportacao thread = new ThreadImportacao(/*passo parametros aqui*/);
		(new Thread(thread)).start();
		
		return (thread.getExecucao() == 1); // esse flag ai indica o que aconteceu durante a importação
	}
Bom, os amigos experientes já notaram que não posso fazer desta forma, isso pq tenho que aguardar até que a thread termine pra só depois pegar o resultado e retornar o método. E antes que perguntem, SIM, tem que ser uma Thread a rotina de importação, por outros motivos que não vou me extender aqui. Então fiz um sistema para aguardar até que a thread termine. Existem muitas formas de se fazer isso, mas vamos usar essa por ex:
public boolean importar(/* meus parametros estao aqui*/){
		
		ThreadImportacao thread = new ThreadImportacao(/*passo parametros aqui*/);
		
		ExecutorService executor = Executors.newSingleThreadExecutor();
		executor.submit(thread);
		
		executor.shutdown();
		while (!executor.isTerminated())
			try { Thread.sleep(1); } catch ( Exception e ) {}
		executor = null;
		
		return (thread.getExecucao() == 1);
	}
Já tentei de várias formas, e em todas tenho o mesmo problema. Ai no exemplo fiz usando executor, já tentei fazendo um loop pra aguardar até que o flag mude pro que preciso, enfim,,, de qq forma obtenho o mesmo problema. O problema está num tal de um JFileChooser que tenho dentro da tal ThreadImportacao. Num dado momento, as vezes, dependendo de diversas condições que só saberei dentro da ThreadImportacao, ele precisa abrir um JFileChooser pro usuário escolher um arquivo. Quando isso acontece, ele abre o JFileChooser travado, assim, fica só o contorno do dialog e tudo branco dentro, sem dar pra clicar em nada. Eu vejo que por tras, as outras rotinas estão rodando normalmente. É como se o swing se perdesse pra apresentar a tela do JFileChooser. (Esqueci de falar, uso Swing).

O que não entendo é que isso só se eu tiver algum sistema pra esperar a thread terminar. Se eu disparar a thread direto, sem ficar aguardando seu fim, o JFileChooser funciona perfeitamente.

Eu consegui fazer um sistema, onde eu disparo a thread de importação e depois eu disparo outra thread, uma thread de espera. Ele funciona, não trava o JFileChooser, mas ai claro, eu não tenho como saber que a thread de espera terminou pra poder pegar o retorno no método. Então caio na mesma encrenca... :cry:

Alguém sabe o que acontece? Como posso resolver isso?

Grata,
Renata

4 Respostas

R

O método importar() está sendo disparado a partir de sua própria Thread? É importante que ele NÃO esteja sendo disparado a partir da EDT (Event Dispatching Thread) do Swing, o que pode causar comportamentos erráticos. E, quando for exibir o seu JFileChooser, não se esqueça de fazê-lo via SwingUtilities.invokeLater() ou SwingUtilities.invokeAndWait().

RenataFA

Olá Roger, obrigada por responder.

O método importar() está sendo disparado através de um ActionListener, no actionPerformed de um JButton.

Tentei fazer como vc falou, chamar o JFileChooser via invokeLater, mas o comportamento foi o mesmo. Aliás, notei que não ocorre apenas com JFileChooser, qq dialog apresentado dentro da ThreadImportacao. Por ex, tenho uns JOptionPane.showOptionDialog usados para dar mensagens de erro/consistência… etc… e acontece exatamente o mesmo, ficam lá, em branco, só o contorno da janela.

Lembre-se que isso apenas se eu de alguma forma ficar esperando a ThreadImportacao terminar. Se apenas dispará-la, funciona perfeitamente sem qq problema. Não é estranho?!

Grata,
Renata

R

Se o método importar() está sendo disparado a partir de um ActionListener, então ele está sendo disparado dentro da EDT do Swing (eu gosto de chamá-la de “a thread da discórdia”). O método importar() fica preso num laço de espera ocupada (“spinlock”) ao chamar continuamente executor.isTerminated(). Enquanto esse spinlock estiver em execução, travando a EDT, todo e qualquer processamento gráfico do Swing ficará em espera, o que creio que explica o comportamento errático do JFileChooser. Sugiro que você dispare o método importar() em sua própria thread:

private void botaoActionPerformed(java.awt.event.ActionEvent evt) {                                      
  Runnable run = new Runnable() {
    public void run() {
      importar();
    }
  };
  new Thread(run).start();
}
RenataFA

Perfeito Roger!

Era exatamente como vc explicou.

Agradeço muito a ajuda! :stuck_out_tongue:

[]'s
Renata

Criado 10 de fevereiro de 2011
Ultima resposta 11 de fev. de 2011
Respostas 4
Participantes 2