Ejemplos de Threads en Applets

Esta página explica dos ejemplos de la utilización de threads en un applet. El primer applet, AnimatorApplet, muestra como utilizar un thread para realizar una tarea repetitiva. El applet AnimatorApplet viene de la página Crear un Bucle de Animación. El segundo applet de esta página, SoundExample, muestra como utilizar threads para tareas de inicailización de una sóla vez. El applet SoundExample se encuentra en la página Ejecutar Sonidos.

Esta página no explica el código básico de los threads. Para aprender algo más acerca de la implementación de los threads en Java, puedes referirte a threads de Control

Utilizar un thread para Realizar Tareas Repetitivas.

Normalmente, un applet que realiza la misma tarea una y otra vez debería tener un thread con un blucle while (o do...while) que realice la tarea. Un ejemplo típico es un applet que realiza una animación temporizada, como un visualizador de películas o un juego. Un applet de animación necesita un thread que le pida redibujarse a intervalos regulares.

Normalmente los applets crean los threads para las tareas repetitivas en el método start(). Crear el thread aquí hace muy fácil que el applet pueda parar el thread cuando el usuario abandone la página. Todo lo que se tiene que hacer es implementar el método stop() para que él detenga el thread del applet. Cuando el usuario retorne a la página del applet, se llama de nuevo al método start(), y el applet puede crear de nuevo el thread para realizar la tarea repetitiva.

Lo que puedes ver más abajo es la implementación de los métodos start() y stop() en la clase AnimatorApplet. (Aquí tienes todo el código fuente del applet.)

public void start() {
    if (frozen) {
        //No hace Nada. El usuario ha pedido que se pare la animación
    } else {
        //Empezar la animación!
        if (animatorThread == null) {
            animatorThread = new Thread(this);
        }
        animatorThread.start();
    }
}

public void stop() {
    animatorThread = null;
}
La palabra this en new Thread(this) indica que el applet proporciona el cuerpo del thread. Y hace esto implementado el interface java.lang Runnable, que requiere que el applet proporcione un método run() que forme el cuerpo del thread. Explicaremos el método run() de AnimatorApplet un poco más adelante.

En el applet AnimatorApplet, el navegador no es el único que llama a los métodos start() y stop(). El applet se llama a sí mismo cuando el usuario pulsa con el ratón dentro del área del applet para indicar que la animación debe terminar. El applet utiliza un ejemplar de la variable frozen para seguir la pista de cuando el usuario pide que se pare la animación.

Habrás podido observar que no aparece en ningún sitio ninguna llamada al método stop() en la clase AnimatorApplet. Esto es así porque llamar al método stop() es como si quisiera meterle el thread a golpes por la cabeza. Es una manera drástica de conseguir que el applet deje lo que estaba haciendo. En su lugar, se puede escribir el método run() de forma que el thread salga de una forma adecuada y educada cuando se le golpee en el hombro. Este golpecito en el hombro viene a ser como poner a null un ejemplar de la variable del tipo Thread.

En AnimatorApplet, este ejemplar de la variable se llama animatorThread. El método start() lo activa para referirse a objeto Thread recientemente creado. Cuando el usuario necesite destruir el thread, pone animatorThread a null. Esto no elimina el thread realizando una recolección de basura --no puede haber recolección de basura mientras este ejecutable-- pero como al inicio del bucle, el thread comprueba e valor de animatorThread, y continúa o abandona dependiendo de este valor. Aquí tiene un código revelador:

public void run() {
    . . .
    while (Thread.currentThread() == animatorThread) {
        ...//Muestra un marco de la aplicación.
    }
}

Si animatorThread se refiere al mismo thread que el que está realmente en ejecución el thread continua ejecutandose. Si por el contrario, animatorThread es null, el thread se termina y sale. Si animatorThread se refiere a otro thread, entonces se ha alcanzado una condición de competición: se ha llamado demasiado pronto a start(), antes de llamar a stop() (o este thread a tardado demasiado en su bucle) que start() ha creado otro thread antes de que este thread haya alcanzado el inicio del bucle while. Debido a la condición de competición este thread debería salir.

Para obtener más indormació sobre AnimatorApplet, puedes ir a: Crear un Bucle de Animación.

Usar un thread para realizar Inicializaciones de una Vez

Si su applet necesita realizar alguna incialización que tarde un poco, se debería considerar el modo de realizar esa inicialización en un thread. Por ejemplo, algo que requiera un trabajo de conexión a la red generalmente debería hacerse en un thread en segundo plano (background). Afortunadamente, la carga de imágenes GIF y JPEG se hace automáticamente en brackground (utilizando threads de los que no tienes que preocuparse).

Desafortunadamente la carga de sonido, no está garantizado que se haga en segundo plano. En las implementaciones actuales los métodos de applet getAudioClip no retornan hasta que se han cargado los datos de audio. Como resultado, si se quiere precargar los sonidos, podría crear una o más tareas para hacer esto.

Utilizar un thread para realizar una tarea de inicialización en un applet es una variación del típico escenaro productor/consumidor. El thread que realiza la tarea es el productor, y el applet el consumidor. Sincronizar threads explica como utilizar los threads de Java en un escenario productor/consumidor.

El applet SoundExample se adhiere al modelo presentado en Sincronizar threads. Como el ejemplo anterior, el applet se caracteriza por tres classes:

  • El productor SoundLoader, una subclase Thread.
  • El consumidor: SoundExample,una subclase Applet. Al contrario que el consumidor en el ejemplo de sincronización de tareas, SoundExamlple no es un Thread; incluso tampoco implementa el interface ejecutable. Sin embargo, al menos, dos threads llaman a los ejemplares de los métodos de SoundExample dependiendo de la aplicación que ejecute el applet.
  • El almacenaje del Objeto: SoundList, Una subclase Hashtable. Al contrario que en el ejemplo de Sincronizar Tareas SoundList puede devolver valores nulos si los datos del sonido no se han almacenado todavia. Esto tiene sentido porque necesita estar disponible para reaccionar inmediatamente a una petición del usuario de que ejecute el sonido, incluso si el sonido no se ha cargado todavia.
Para más información sobre el SoundExample, puedes ir a Ejecutar Sonidos


Ozito