Cómo usar Threads

Esta página ofrece algunos ejemplos de uso de threads relacionados con el API de Swing. Para información concpetual, puedes ver Threads y Swing.

Usar el método invokeLater

Podemos llamar al método invokeLater desde cualquier thread para pedir que el thread de despacho de eventos ejecute cierto código. Debemos poner este código en el método run de un objeto Runnable y especificar ese objeto Runnable como el argumento de invokeLater. El método invokeLater retorna inmediatamente, sin esperar a que el thread de despacho de eventos ejecute el código. Aquí hay un ejemplo de uso de invokeLater>
Runnable doWorkRunnable = new Runnable() {
    public void run() { doWork(); }
};
SwingUtilities.invokeLater(doWorkRunnable);

Usar el método invokeAndWait

El método invokeAndWait es exacatamente igual que invokeLater, excepto en que no retorna hasta que el thread de despacho de eventos haya ejecutado el código especificado. Siempre que sea posible debemos usar invokeLater en vez de invokeAndWait. Si usamos invokeAndWait, debemos asegurarnos de que el thread que llama a invokeAndWait no contiene ningún bloqueo que otros threads podrían necesitar mientras ocurra la llamada. Aquí hay un ejemplo de uso de invokeAndWait:
void showHelloThereDialog() throws Exception {
    Runnable showModalDialog = new Runnable() {
        public void run() {
            JOptionPane.showMessageDialog(myMainFrame,
	                                  "Hello There");
        }
    };
    SwingUtilities.invokeAndWait(showModalDialog);
}
De forma similar, un thread que necesite acceso al estado del GUI, como el contenido de un par de campos de texto, podría tener el siguiente código:
void printTextField() throws Exception {
    final String[] myStrings = new String[2];

    Runnable getTextFieldText = new Runnable() {
        public void run() {
            myStrings[0] = textField0.getText();
            myStrings[1] = textField1.getText();
        }
    };
    SwingUtilities.invokeAndWait(getTextFieldText);

    System.out.println(myStrings[0] + " " + myStrings[1]);
}

Cómo Crear Threads

Si podemos evitarlo, no debemos usar threads. Los threads pueden ser difíciles de usar, y hacen los programas muy duros de depurar. En general, no son necesarior para el trabajo estricto del GUIm como actualizar las propiedades de un componente.

Sin embargo, algunas veces, los threads son necesarios. Aquí tenemos algunas situaciones típicas en las que se usan threads:

  • Para realizar tareas que llevan mucho tiempo sin bloquear el thread de despacho de eventos (ejemplos de esto pueden ser los cálculos intensivos, o las tareas de inicialización).
  • Para realizar una operación de forma repetida, normalmente con periodo de tiempo dererminado entre operaciones.
  • Para esperar mensajes de clientes.

Podemos usar dos clases para ayudarnos a implementar threads:

  • SwingWorker: Crea un thread en segundo plado que ejecuta operaciones que consumen mucho tiempo.
  • Timer: Crea un thread que ejecuta algún código una o más veces, con un retardo especificado por el usuario entre cada ejecución. Para más información sobre los timers, puedes ver Cómo usar Timers.

Usar la clase SwingWorker

La clase SwingWorker está implementada en SwingWorker.java, que no está en la versión Swing. SwingWorker hace todo el trabajo sucio de implementar un thread en segundo plano. Aunque muchos programas no necesitan este tipo de threads, son muy útiles para realizar tareas que consumen mucho tiempo, y pueden aumentar el rendimiento percibido del programa.

Para usar la clase SwingWorker, primero debemos crear una subclase de ella. En la subclase, debemos implementar el método construct para que contenga el código que realiza la operación. cuando ejemplarizemos nuestra subclase de SwingWorker, SwingWorker crea un thread que llama a nuestro método construct. Cuando necesitemos el objeto devuelto por el método construct, llamaremos al método get de SwingWorker. Aquí tenemos un ejemplo de uso de SwingWorker:

...//in the main method:
    final SwingWorker worker = new SwingWorker() {
        public Object construct() {
            return new ExpensiveDialogComponent();
        }
    };

...//in an action event handler:
    JOptionPane.showMessageDialog
        (f, worker.get());
Cuando el método main del programa crea el objeto SwingWorker, inmediatamente se arranca un nuevo thread que ejemplariza ExpensiveDialogComponent. El método main también construye un GUI que consiste en una ventana con un botón.

Cuando el usuario pulsa el botón, el programa se bloquea, si es necesario, hasta que se haya crreado ExpensiveDialogComponent. Entonces el programa muestra el dialo modal que contiene ExpensiveDialogComponent. Puedes encontrar el programa completo en PasswordDemo.java. También, el programa de ejemplo propocionado en Cómo Monitorizar el Progreso ejecuta una larga tarea en un theead SwingWorker.


Está sección está basada en un artículo de La Conexión Swing. Para más informaicón sobre los problemas con los Threads en Swing, puedes ver el artículo Threads y Swing.

Ozito