domingo, 16 de octubre de 2011

Interfaces de Usuario Swing con Hilos

En esta entrada quiero compartir algunos problemas de subprocesamiento multiples  (ejecución de tareas en paralelo) relacionados con la programacion de interfaces graficas de usuarios.

Hilos en Swing
Una de las razones de usar hilos en tus aplicaciones es la de hacer que tu aplicacion sea mas interactivo. Cuando tu aplicacion realiza una tarea que requiere mucho tiempo, más de dos segundos a mi juicio, entonces debes ejecutar la tarea en otro hilo para evitar que la interfaz de usuario se quede "congelada".

Hay un hilo diseñado exclusivamente para pintar la interfaz grafica y para procesar los eventos del usuario, este hilo es conocido como el EDT (Event Dispatch Thread), todo código que requiera manipular componentes swing debe ser ejecutado en este hilo, de no hacerlo así te puedes llevar varias sorpresas. Swing es not thread safe. Es decir, la mayoria de los metodos de las clases Swing no son sincronizados. Si tu intentas manipular los elementos de la interfaz grafica del usuario desde varios hilos entonces la interfaz de usuario se dañara.

Evolución del Multiprocesamiento en Java
Me inicié en el mundo Java por los años 2008, han pasado ya casí 10 años y he visto como Java ha ido creciendo y evolucionando para facilitarle las tareas al programador. Antes de la versión 1.6, para ejecutar tareas en paralelo tenías que extender explicitamente a la clase Thread y programar toda la lógica del subprocesamiento multiple, sincronización, interacción con la GUI y demás. Con la llegada de la versión 1.6 aparece una clase llamada SwingWorker el cual se encarga de manejar toda la logica del subprocesamiento en paralelo, facilitandote en mucho la programación.

Resumiendo, hay dos formas de programar el subprocesamiento multiple con Swing.
  1. La forma tradicional en la que extiendes a Thread y programas toda la lógica de hilos.
  2. Extendiendo la clase SwingWorker

Yo recomiendo la segunda, usando la clase SwingWorker.
Para profundizar en el hilo EDT y SwingWorker puedes leer mi entrada SwingWorker y el Hilo que despacha los Eventos ahí explico detalladamente estás dos clases.

Problemas más comunes con sub procesamiento multiple

Por ejemplo corre el siguiente programa.

package com.maro.gui;

import java.util.Random;

import javax.swing.JComboBox;

public class BadWorkerThread extends Thread {

public BadWorkerThread(JComboBox aCombo){
combo = aCombo;
generator = new Random();
}
public void run(){
try {
while (!interrupted()){
int i = Math.abs(generator.nextInt());
if(i % 2 == 0){
combo.insertItemAt(new Integer(i), 0);
} else if(combo.getItemCount() > 0){
combo.removeItemAt(i % combo.getItemCount());
}
sleep(1);
}
} catch(InterruptedException iee){
}
}
private JComboBox combo;
private Random generator;
}


Un frame para visualizarlo, una vez que corras el programa presiona el boton "Bad" y juega con el combo box, notaras que el compilador lanza varias excepciones.

package com.maro.gui;

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class TestBadWorkerThread extends JFrame{

private JComboBox combo;
private Thread longTask;
public TestBadWorkerThread (){
super("Prueba");
combo = new JComboBox();
JPanel contentPanel = new JPanel();
contentPanel.setLayout(new FlowLayout());
JButton badButton = new JButton("Bad");
badButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
longTask = new BadWorkerThread(combo);
longTask.start();
}
});
contentPanel.add(badButton);
contentPanel.add(combo);
this.getContentPane().add(contentPanel);
this.pack();
//this.setVisible(true);
}
public static void main(String args[]){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// TODO Auto-generated method stub
TestBadWorkerThread pr = new TestBadWorkerThread();
pr.setVisible(true);
}
});
}
}

No hay comentarios:

Publicar un comentario