Ejecución multihilo en applets
Hasta ahora sólo disponíamos de un hilo de ejecución. Es decir, en
nuestros programas sólo se ejecuta una cosa al tiempo. Si deseamos que se
ejecuten varias cosas a la vez o simplemente deseamos disponer de una manera
precisa de controlar la ejecución de parte de nuestro programa dependiendo del
tiempo, necesitaremos que nuestro applet realice una ejecución multihilo.
El concepto de multitarea es diferente al de multihilo. El primero se
suele aplicar a la ejecución concurrente de programas distintos, ya que para
que exista multitarea se exige que cada proceso ejecutándose disponga de su
propio espacio en la memoria. En el segundo caso, en cambio, todos los hilos
que se ejecutan concurrentemente disponen del mismo espacio de memoria.
Pero no vamos a escribir un tratado filosófico sobre las diversas formas
de programación concurrente. Lo mejor que podemos hacer es explicarlo sobre un
ejemplo. El ejemplo siguiente es una modificación del applet
MostrarMensaje, realizado anteriormente, que
realiza un scroll lateral del texto, que aparece por la derecha y desaparece
por la izquierda. El código nuevo que concierne a la ejecución multihilo está
en negrita para facilitar su identificación:
Rotacion.java
/**
* Applet MostrarCadena
*
* <APPLET CODE="MostrarCadena.class" WIDTH="200" HEIGHT="70">
* <PARAM NAME="Cadena" VALUE="Esto sí que es chulo">
* </APPLET>
*/
import java.applet.Applet;
import java.awt.*;
public class MostrarCadena extends Applet implements Runnable {
String mensaje;
int lugar;
Thread hilo = null;
public void init() {
mensaje = getParameter("cadena");
if (mensaje==null)
mensaje = "Mensaje por defecto";
lugar = getBounds().width;
}
public void start() {
if (hilo==null) {
hilo = new Thread(this);
hilo.start();
}
}
public void stop() {
hilo = null;
}
public void paint(Graphics g) {
g.drawString(mensaje,lugar,20);
}
public void run() {
while (hilo!=null && hilo.isAlive()) {
lugar -= 1;
repaint();
try {
hilo.sleep(10);
}
catch (InterruptedException e) {} // No hacemos nada
}
}
}
Lo primero es asegurarnos que nuestro applet implementa el interfaz
Runnable, necesario para el soporte de threads,
o hilos de ejecución. Después declaramos un objeto de tipo
Thread, es decir, hilo, y lo igualamos a
null. En el método
start(), que es donde debe "estart" todo el
código de inicialización, creamos el hilo y lo arrancamos llamando a su método
start(). En stop(),
por el contrario, lo paramos.
El método run() es nuevo y es consecuencia
de la implementación del interfaz Runnable.
Cuando creamos un hilo de ejecución, como hemos hecho en
start(), el hilo recién creado siempre comienza
su vida útil ejecutando el método run(). Así
pues, aquí estará el código del hilo. Comenzamos preguntando si existe nuestro
hilo (hilo!=null) y si
está ejecutandose (isAlive).
Luego mueve el texto un poco a la izquierda, repinta, y se obliga a sí
mismo a dejar de ejecutarse durante 10 milisegundos por medio del método
sleep(). Transcurrido ese tiempo seguirá su
ejecución por el mismo sitio donde la dejó (de ahí que sea necesario el
while).
Indicar por último que es obligatorio capturar la excepción
InterruptedException para poder llamar al método
sleep(). En caso contrario el compilador se
queja. Así pues, lo hacemos, aunque no especifiquemos ningún código en caso de
que se lance dicha excepción. Esto ocurrirá en casos muy excepcionales, por lo
que no debemos preocuparnos.