Pq utilizar SwngUtilies.InvokeLater()? [Resolvido]

               Bom dia, estou confuso com o método [i]invokeLater[/i], estudei sobre [i]SwingWorker[/i] e entendi sobre a [i]thread trabalhadora[/i], mas eu achava que só pelo fato de vc criar uma classe sem o [i]SwingWorker[/i] a GUI já seria executada na [i]thread de despacho de eventos[/i], por exemplo:
private JTextField  texto =  new JTextField(15);
public void teste()
      {
             texto.setText("hello"); // isso seria executado na thread de despacho de eventos normalmente, sem a necessidade do método invokeLater
      }

Mas então eu vi a utilização do método invokeLater e fiquei confuso, pq utiliza-lo para executar em uma thread de despacho de eventos se o código acima já faz isso sem esse método? Então não seria o caso de sempre utilizar o método invokeLater sempre que eu quisesse que a GUI fosse executada na thread de despacho de eventos? O método acima esta errado por não estar sendo executado pelo método invokeLater?

Método invokeLater

private void teste()
         {
               SwingUtilities.invokeLater(
                                                                    new Runnable()
                                                                            {
                                                                                      public void run()
                                                                                               {
                                                                                                         texto.setText("hello"); 
                                                                                                         /* para ser executado na thread de despacho de eventos, mas o exemplo anterior já não faz isso !?*/
                                                                                               }
                                                                            }
                                                        )
        }

Comandos de atualização de tela só podem ser utilizados na thread do Swing, pois nenhum componente Swing é thread-safe.
Quando você cria uma thread separada, todos os comandos dados nela são executados nessa thread, e não mais na thread do Swing.

Acontece que o Swing tem uma fila, que ele usa para processar requisições. A própria thread do swing processa essa fila. Você pode imaginar a thread do swing como um while da seguinte forma:

while (true) { processaFilaDeMensagens(); processaEventos(); repintaATela(); }

No caso, os métodos SwingUtilities.invokeAndWait e SwingUtilities.invokeLater (ou de mesmo nome na classe EventQueue) simplesmente empilham requisições nessa fila.
Esse empilhamento sim, é feito de maneira thread-safe.

Assim, se você está na thread trabalhadora e precisa atualizar uma caixa de texto, você deverá faze-lo através de uma requisição:

EventQueue.invokeLater(new Runnable() { @Override public void run() { seuTexto.setText("Isso rodará na thread do Swing!"); } });

Note que isso não cria novas threads. Isso apenas enfilera um runnable, que será processado na thread do Swing. Você pode imaginar o método processaFilaDeMensagens como sendo assim:

void processaFilaDeMensagens() {
   for (Runnable mensagem : filaDeMensagens) {
       mensagem.run();
   }
}

A exceção são apenas alguns métodos, de alguns componentes, como é o caso do método append do JTextArea.
Nesses métodos há um texto no Javadoc explicando que são thread-safe.

A Sun optou por fazer dessa forma pois torna a implementação de componentes por terceiros mais simples, já que não é necessário considerar questões de thread-safety (afinal, dessa forma componentes só rodam por uma única thread, a do Swing). Dessa forma, é mais fácil também fazer extensão dos componentes através de herança, uma vez que quem implementa a classe filha não precisa estudar em detalhes como o pai faz sincronização.

Observe que os actionListener de botões já são executados na thread do swing, portanto, neles você não precisa usar o invokeLater ou o invokeAndWait para nada. E também não se esqueça que a main thread não é a thread do Swing. Por isso as IDEs inserem automaticamente o código para tornar a primeira janela visível dentro do invokeLater.

1 curtida

Entendi. Obrigado.