• No results found

Oja median and depth

Antes de estudiar cómo crear hilos, primero vamos a definir este término. La mayoría de las máquinas disponen de un único procesador para asegurar su funcionamiento. Por supuesto, este procesador sólo

puede realizar una operación elemental a la vez, y sin embargo con la mayoría de los sistemas operativos podemos ejecutar varias aplicaciones de manera simultánea. De hecho, tenemos la sensación que varias aplicaciones se ejecutan a la vez, pero en realidad no es así. Para simular esta simultaneidad, el sistema operativo "corta" el tiempo procesador disponible en capas muy finas y las distribuye a las diferentes aplicaciones. La conmutación es tan rápida que tenemos la sensación de que todas las aplicaciones se ejecutan a la vez. La programación multithilo aplica este mismo principio a una aplicación. Si cogemos el ejemplo de tratamiento de texto, éste puede efectuar por ejemplo varias operaciones a la vez (introducción de texto, verificación de la ortografía, configuración de la página, impresión…).

Para poder efectuar todos estos tratamientos, la aplicación realiza de nuevo un recorte de cada capa de tiempo de procesador que le proporciona el sistema operativo y asigna una porción de esta capa para cada tarea que se debe realizar.

Por defecto, una aplicación o un applet está asociado a un hilo responsable de la ejecución de nuestro código. A veces se le llama hilo principal. Puede ser a veces útil añadir uno o varios hilos adicionales para conservar un buen nivel de dinamismo de la aplicación. En el caso de un applet, podemos añadir por ejemplo un hilo para efectuar una operación de inicialización relativamente larga. Si esta operación se efectúa con el método init del applet, el navegador tendrá que esperar el fin de este método para proseguir el lanzamiento del applet. En cambio, si desde el método initlanzamos un nuevo hilo para efectuar la operación de inicialización, el resto del lanzamiento del applet se ejecutará más rápidamente mientras el hilo siga efectuando la inicialización. Esta técnica es muy útil para un applet que utiliza ficheros de sonidos. Así se puede descargar el fichero mientras se prosigue la inicialización del applet.

http://www.eni-training.com/client_net/mediabook.aspx?idR=65890 16/20

public class ThreadPerso extends Thread {

public void run() {

// código a ejecutar por el hilo }

}

Thread t;

t=new Thread(){

public void run() {

// código a ejecutar por el hilo }

};

Los hilos son también muy útiles cuando un applet debe realizar un tratamiento repetitivo. Podemos confiar a un nuevo hilo la tarea de ejecutar este tratamiento sin molestar el funcionamiento del resto del applet.

La utilización de los hilos necesita tres etapas en el diseño de la aplicación: crear un nuevo hilo,

definir el tratamiento que debe efectuar el nuevo hilo, gestionar los lanzamientos y paros del hilo.

A continuación, el detalle de estas tres etapas.

a. Creación de un nuevo hilo

La clase Thread permite la creación y la gestión de un hilo. Como para cualquier otra clase, hay que crear una instancia vía uno de los constructores disponibles. Es importante señalar que la creación de una instancia de la clase Thread no activa el lanzamiento de la ejecución del hilo.

b. Definir el tratamiento a efectuar

Cuando se lanza un hilo, éste ejecuta automáticamente su método run. Por defecto este método se define en la clase Thread pero no contiene ningún código. Por lo tanto, es obligatorio volver a definir este método. Se puede hacer creando una clase que hereda de la clase Thread y definiendo de nuevo en ésta el método run.

Por supuesto en este caso, se tendrá que crear una instancia de esta clase.

También podemos obtener el mismo resultado al crear una instancia de clase interna anónima.

La última solución consiste en indicar al hilo que el método run que debe ejecutar se encuentra en otra clase. En este caso, se debe proporcionar una instancia de esta clase en el momento de la llamada del constructor de la clase Thread. Para asegurarse de que la clase utilizada contiene en efecto un método run, ésta deberá implementar la interfaz Runnable. La clase del applet se puede encargar de ello.

public class TestApplet5 extends Applet implements Runnable {

Thread th;

public void run() {

// código a ejecutar por el hilo }

public void start() {

th=new Thread(this); }

}

public void run() {

Thread t;

t= Thread.currentThread(); while(th==t)

{

// código a ejecutar por el hilo } } Thread t; t= Thread.currentThread(); while(th==t) {

// código a ejecutar por el hilo // duerme el hilo durante 500 ms try

{

Thread.sleep(500); }

catch (InterruptedException e){} }

El método run ejecuta un tratamiento único en este caso, se concibe como un método clásico y su ejecución terminará con la última instrucción de este método.

El método run ejecuta un tratamiento cíclico y en este caso debe contener un bucle que termina con la desaparición del hilo que lo ejecuta. Se puede utilizar por ejemplo la sintaxis siguiente para este bucle.

Al permitir el método estático currentThread obtener una referencia en el hilo actual, el bucle terminará en cuanto la variable th no haga más referencia al hilo actual. Será el caso, por ejemplo, si se asigna el valor null a esta variable.

A veces puede ser necesario controlar la frecuencia de ejecución de las instrucciones del bucle al insertar en él una llamada al método estático sleep de la clase Thread. Esta método "duerme" el hilo actual durante el número de milisegundos que se le da como parámetro. La llamada a este método se debe proteger con un bloque try catch.

http://www.eni-training.com/client_net/mediabook.aspx?idR=65890 18/20

import java.applet.Applet; import java.awt.Graphics; import java.awt.Image;

public class TestApplet5 extends Applet implements Runnable {

Thread th;

final int MAXI=100; final int MINI=10; int anchura=MINI; int altura=MINI; Imagen img;

public void run() { boolean engordar=true; Thread t; t=Thread.currentThread(); while (th==t) {

if(anchura>MAXI & engordar) {

engordar=false; }

if (anchura<MINI & !engordar) { engordar=true; } if (engordar) { anchura++; altura++; } else { anchura--; altura--; } repaint(); try { th.sleep(10);

c. Lanzar y parar un hilo

El lanzamiento de un hilo se activa con una llamada a su método start. Esta llamada provoca la ejecución del método run del hilo. En ningún caso se debe llamar directamente al método run del hilo porque se ejecutaría por el hilo actual (el principal) del applet. Esto reduciría nuestros esfuerzos a nada e incluso podría provocar el bloqueo del applet si el método run contuviera un bucle (al no poder ejecutarse más el código que permite hacer evolucionar la condición de salida del bucle ya que en este caso la ejecución del método run monopoliza el hilo principal).

El detención del hilo está provocada por el fin de la ejecución de su método run ya sea porque la última instrucción que contiene terminó o porque el bucle que contiene terminó. El método stop, a pesar de estar presente en la clase Thread, no debe ser utilizado ya que conlleva riesgos de bloqueo de la aplicación.

Para ilustrar la utilización de los hilos, a continuación veremos un applet que permite engordar y adelgazar Duke de manera continua.

} catch (InterruptedException e) {} } }

public void init() {

img=getImage(getCodeBase(),"imágenes/duke.gif"); }

public void start() {

th=new Thread(this); th.start();

}

public void stop() {

th=null; }

public void paint(Graphics g) {

g.drawImage(img,30,0,anchura,altura,this); }

}

import java.applet.Applet;

5. Los sonidos en los applets

La clase Applet propone dos métodos que permiten la carga de un fichero de audio. El métodogetAudioClip sólo puede ser invocado desde un applet, mientras que el método newAudioClippuede serlo desde cualquier tipo de aplicación ya que se declara static en la clase Applet y por lo tanto se vuelve accesible sin que exista una instancia de la clase Applet. Estos dos métodos aceptan como argumento un objeto URL que representa la ubicación del fichero audio. También está disponible la sobrecarga del método getAudioClip que acepta como segundo parámetro una cadena de caracteres. Este segundo parámetro representa la ruta relativa a la URL dada como primer parámetro para obtener el fichero de audio. Este método es muy útil porque permite emplear los métodos getCodeBase o getDocumentBase para obtener la URL del applet o la URL de la página html y luego especificar la ruta de acceso al fichero de audio en relación con esta URL. Estos métodos devuelven una instancia de clase que implementa la interfaz AudioClip. Esta interfaz define los métodos play, loop y stop que permiten escuchar el fichero audio una vez, en bucle o pararlo. Los sonidos en los applets deben ser usados con moderación y precaución bajo pena de enfadar rápidamente al usuario del applet. Por ejemplo hay que tener en cuenta que los ficheros de audio son a veces voluminosos y por ello tardan en ser descargados. Si el método getAudioClipse utiliza en el método init del applet, habrá que esperar el final de la descarga del fichero de audio para que el applet se pueda utilizar. Es preferible lanzar, en este método init, un hilo responsable de descargar el fichero audio y lanzar su restitución al final de la descarga.

También hay que recordar que la máquina virtual Java del navegador conserva las instancias de los applets creados hasta el cierre del navegador. Si un applet ejecutó el método loop en un objetoAudioClip, se restituirá el fichero en bucle hasta el cierre del navegador incluso si el usuario navega por una página diferente de la que contiene el applet. Por lo tanto es prudente llamar al método stop del objeto AudioClip en el método stop del applet.

http://www.eni-training.com/client_net/mediabook.aspx?idR=65890 20/20

import java.applet.AudioClip;

public class TestAppletAudio extends Applet implements Runnable {

AudioClip ac; public void init() {

Thread th;

th=new Thread(this); th.start();

}

public void start() { if (ac!=null) { ac.loop(); } }

public void stop() { if (ac!=null) { ac.stop(); } }

public void run() {

ac=getAudioClip(getCodeBase(),"sonido.wav"); ac.loop();

} }