Esta p�gina explica como usar el API Swing de forma segura con threads. Si nuestro programa es un applet, lo m�s seguro es construir su GUI en el m�todo init. Si nuestro programa es una aplicaci�n con el siguiente patr�n com�n estaremos seguros.
//Thread-safe example public class MyApplication { public static void main(String[] args) { JFrame f = new JFrame(...); ...//Add components to the frame here... f.pack(); f.setVisible(true); //Don't do any more GUI work here. } ... //All manipulation of the GUI -- setText, getText, etc. -- //is performed in event handlers such as actionPerformed(). ... }
Sin embargo, si nuestro programa crea threads que realizan tareas que afectan al GUI, o manipulan un GUI ya visible en respuesta a alg�n evento del AWT, �sigue leyendo!
- La Regla de los Threads
- Los componentes Swing solo pueden ser accedidos por un thread a la vez. Generalmente, este thread es el que despacha los eventos.
- Excepciones a la Regla
- Unas pocas operaciones est�n garantizadas como seguras ante los threads.
- C�mo Ejecutar C�digo en el Thread de Despacho de Eventos
- Si necesitamos acceder al UI desde fuera del c�digo del despachador de eventos o de dibujo, podemos usar los m�todos invokeLater o invokeAndWait.
- C�mo crear Threads
- Si necesitamos crear un thread -- por ejemplo para manejar un trabajo que gasta mucho tiempo o paquetes de I/O -- podemos usar uno de los thread �tiles como SwingWorker o Timer.
�La Regla de los Threads
La Regla de los Threads es la siguiente.
Regla: Una vez que se haya realizado un componente Swing, todo el c�digo que pudiera afectar o depender del estado de ese componente deber�a ejecutarse en el thread de despacho de eventos. |
Esta regla podr�a sonar espeluznante, pero para la mayor�a de los programas sencillos, no tenemos que preocuparnos de los threads. Antes de entrar en detalles sobre c�mo escribir c�digo Swing, definiremos dos t�rminos: realizado y thread de despacho de eventos.
Realizado significa que el m�todo paint del componente haya sido o podr�a ser llamado. Un componente Swing que sea una ventana de alto nivel se realiza habiendo llamado a uno de estos m�todos sobre ella: setVisible(true), show, o (lo que podr�a sorprendernos) pack. Una vez que una ventana se ha realizado, todos los componentes que contiene est�n realizados. Otra forma de realizar un componente es a�adirlo a un componente que ya est� realizado.
El thread de despacho de eventos es el thead que ejecuta el c�digo de dibujo y de despacho de eventos. Por ejemplo los m�todos paint y actionPerformed se ejecutan autom�ticamente en el thread de despacho de eventos. Otra forma de ejecutar c�digo en el thread de despacho de eventos es usar el m�todo invokeLater de SwingUtilities.
�Excepciones a la Regla
Existen unas pocas excepciones a la regla de que todo el c�digo que afecte a un componente Swing realizado debe ejecutare en el thread de despacho de eventos.
- Unos pocos m�todos de threads seguros.
- En la Documentaci�n del API Swing, los m�todos de threads seguros est�n marcados con este texto. Este m�todo es seguro ante los threads, aunque muchos m�todos Swing no lo son. Por favor lea Threads and Swing para m�s informaci�n.
- Un GUI de una aplicaci�n frecuentemente puede ser construido y mostrado en el thread principal.
- Mientras que no se haya realizado ning�n componente (Swing o de otro tipo) en el entorno de ejecuci�n actual, est� construir y mostrar un GUI en el thread principal de una aplicaci�n. Para ayudarnos a ver por qu�, aqu� hay un an�lisis del thread seguro de
thread-safe example. Para refrescar nuestra memoria, aqu� est�n las l�neas m�s importantes del ejemplo.
public static void main(String[] args) { JFrame f = new JFrame(...); ...//Add components to the frame here... f.pack(); f.setVisible(true); //Don't do any more GUI work here. }
- El ejemplo construye el GUI en el thread principal. En general, podemos construir (pero no mostrar) un GUI en cualquier thread, mientras que no hagamos llamadas que se refieran o afecten a los componentes ya realizados.
- Los componentes en el GUI son realizados por la llamada a pack.
- Inmediatamente despu�s, los componentes el GUI son mostrados con la llamada a setVisible (o show). T�cnicamente, la llamada a setVisible es insegura porque los componentes ya han sido realizados por la llamada a pack. Sin embargo, como el programa no ha hecho visible el GUI todav�a, es sumamente contrario a que una llamada a paint ocurra antes de que retorne setVisible.
- El thread principal no ejecuta c�digo GUI despu�s de llamar a setVisible. Esto significa que el c�digo del GUI se mueve del thread principal al thread de despacho de eventos, y el ejemplo es, en la pr�ctica, de thread seguro.
- Un GUI de un applet puede contruirse y mostrarse en el m�todo init.
- Los navegadores existentes no dibujan el applet hasta despu�s de que hayan sido llamados los m�todos init y start. As�, construir el GUI en el m�todo init del applet es seguro, siempre que no llames a show() o setVisible(true) sobre el objeto applet actual.
Por supuesto, los applets que usan componentes Swing deben ser implementados como subclases de JApplet, y los componentes deben ser a�adidos al panel de contenido del JApplet, en vez de directamente al JApplet. Al igual que para cualquier applet, nunca deber�amos realizar inicializaci�n que consuma mucho tiempo en los m�todos init o start; en su lugar deber�amos arrancar un thread que realice las tareas que consuman tiempo.
- Los siguientes m�todos de JComponent son seguros para llamarlos desde cualquier thread: repaint, revalidate, e invalidate.
- Los m�todos repaint y revalidate envian peticiones para que el thread de despacho de eventos llame a paint y validate, respectivamente. El m�todo invalidate s�lo marca un componentes y se requiere la validaci�n de todos sus ancestros.
- Oyentes que pueden ser modificados desde cualquier thread
- Es siempre seguro llamar a los m�todos addListenerTypeListener y removeListenerTypeListener. Las operaciones de a�adir/eliminar no tienen ning�n efecto en el despacho de eventos,
�C�mo Ejecutar C�digo en el Thread de Despacho de Eventos
La mayor parte del trabajo de post-inicializaci�n de un GUI naturalmente ocurre en el thread de despacho de eventos. Una vez que el GUI es visible, la mayor�a de los programas son conducidos por eventos como acciones de botones o clicks del rat�n, que siempre son manejados por el thread de despacho de eventos.
Sin embargo, algunos programas necesitan realizar alg�n trabajo de GUI no conducido por eventos, despu�s de que el GUI sea visible. Aqu� tenemos algunos ejemplos.
- Programas que deben realizar una operaci�n de inicializaci�n larga antes de poder ser usados:
- Esta clase de programas generalmente deber�a mostrar alg�n GUI mientras est� ocurriendo la inicializaci�n, y luego actualizar o cambiar el GUI. La inicializaci�n no deber�a ocurrir en el thread de despacho de eventos; si no el repintado y el despacho de eventos se parar�an. Sin embargo, despu�s de la inicializaci�n el cambio/actualizaci�n del GUI deber�a ocurrir en el thread de despacho de eventos por razones de seguridad con los threads.
- Programas cuyo GUI debe actualizarse como resultado de eventos no-AWT:
- Por ejemplo, supongamos que un programa servidor quiere obtener peticiones de otros programas que podr�an estar ejecut�ndose en diferentes m�quinas. Estas peticiones podr�an venir en cualquier momento, y resultan en llamadas a algunos de los m�todos del servidor en alg�n m�todo thread desconocido. �C�mo puede el m�todo actualizar el GUI? Ejecutando el c�digo de actualizaci�n del GUI en el thread de despacho de eventos.
La clase SwingUtilities proporciona dos m�todos para ayudarnos a ejecutar c�digo en el thread de despacho de eventos.
- invokeLater:
- Pide que alg�n c�digo se ejecute en el thread de despacho de eventos. Este m�todo retorna inmediatamente, sin esperar a que el c�digo sea ejecutado.
- invokeAndWait:
- Act�a igual que invokeLater, excepto en que este m�todo espera a que el c�digo se ejecute. Como regla, deber�amos usar invokeLater en vez de este m�todo.
Para m�s informaic�n sobre el uso de invokeLater y invokeAndWait, y otros trucos para esciribir programas multi-threads, puedes ver C�mo usar Threads.