Universidad Autónoma de Baja California Facultad de Ingeniería Apuntes de Programación Orientada a Objetos I Hilos Hasta el momento los programas que se han estado manejando en el curso han sido secuenciales. Esto es, inician en un punto y continuan su ejecución de manera predecible y en secuencia hasta el final. En un momento dado, solo se esta ejecutando una parte del programa. Se puede decir que un programa con los que se han estado trabajando tiene solo un hilo de ejecución. El lenguaje Java permite escribir programas que al ejecutarse tengan mas de un hilo de ejecución. Esto es, varias secciones del programa se encontrarán en ejecución en un momento dado. Por supuesto que se debe recordar que al tener solo una unidad de procesamiento o microprocesador, en realidad solo se ejecutará una cosa a la vez. Sin embargo, al trabajar con hilos, se puede pensar que en un momento habra varios hilos activos y trabajando. Básicamente un hilo es un proceso ligero que solo puede ejecutarse dentro del contexto de otro proceso que será el programa principal. Esto es, no puede existir unicamente un hilo que se vaya a ejecutar, sino que un hilo solo puede existir si se encuentra ligado a un programa ya que este último se encarga de obtener los recursos necesarios para trabajar dentro del entorno de ejecución. Caso de Estudio Timer Java provee la clase Timer que trabaja conjuntamente con TimerTask para calendarizar eventos que ocurran en sincronía con un reloj. La clase java.util.Timer trabaja internamente con hilos de ejecución. El programa del Listado 1 muestra como se puede calendarizar una tarea para que ésta se ejecute una vez que hayan pasado 5 segundos. La primer sección iluminada muestra como se crea un Timer y se programa un evento. La segunda sección muestra que la clase RemindTask se deriva de TimerTask que a su vez implanta al interfaz Runnable y además se sobrecarga el método run(). 1 de 6 Elaborado por: M.C. Cecilia M. Curlango Rosas Universidad Autónoma de Baja California Facultad de Ingeniería Apuntes de Programación Orientada a Objetos I import java.util.Timer; import java.util.TimerTask; public class Reminder { Timer timer; public Reminder(int seconds) { timer = new Timer(); timer.schedule(new RemindTask(), seconds*1000); } class RemindTask extends TimerTask { public void run() { System.out.println("Time's up!"); timer.cancel(); //Terminate the timer thread } } public static void main(String args[]) { System.out.println("About to schedule task."); new Reminder(5); System.out.println("Task scheduled."); } } Listado 1 Ejemplo del uso de Timer Como agregar hilos a una clase. Para que una clase utilice hilos existen dos posibilidades. Una de ellas es que la clase se derive de la clase java.lang.Thread y que sobrecargue el método run() de ésta. El método run() es un método muy importante en hilos ya que éste es el que se emplea para que indicarle a un hilo lo que debe hacer. El Listado 2 muestra como se puede crear hilos de esta forma. Mientras que el Listado 3 2 de 6 Elaborado por: M.C. Cecilia M. Curlango Rosas Universidad Autónoma de Baja California Facultad de Ingeniería Apuntes de Programación Orientada a Objetos I contiene un programa corto que emplea hilos y prueba la clase del listado Listado 2. public class SimpleThread extends Thread { public SimpleThread(String str) { super(str); } public void run() { for (int i = 0; i < 10; i++) { System.out.println(i + " " + getName()); try { sleep((long)(Math.random() * 1000)); } catch (InterruptedException e) {} } System.out.println("DONE! " + getName()); } } Listado 2 Ejemplo de subclase de Thread y sobrecarga de run public class TwoThreadsDemo { public static void main (String[] args) { new SimpleThread("Jamaica").start(); new SimpleThread("Fiji").start(); new SimpleThread("México").start(); System.out.println("Ahora me espero a la suerte."); } } Listado 3 Ejemplo de uso de hilos. En ocaciones el método de derivar de la clase Thread no puede emplearse 3 de 6 Elaborado por: M.C. Cecilia M. Curlango Rosas Universidad Autónoma de Baja California Facultad de Ingeniería Apuntes de Programación Orientada a Objetos I import java.awt.Graphics; import java.util.*; import java.text.DateFormat; import java.applet.Applet; public class Clock extends Applet implements Runnable { private Thread clockThread = null; public void start() { if (clockThread == null) { clockThread = new Thread(this, "Clock"); clockThread.start(); } } public void run() { Thread myThread = Thread.currentThread(); while (clockThread == myThread) { repaint(); try { Thread.sleep(1000); } catch (InterruptedException e){ // the VM doesn't want us to sleep anymore, // so get back to work } } } public void paint(Graphics g) { // get the time and convert it to a date Calendar cal = Calendar.getInstance(); Date date = cal.getTime(); // format it and display it DateFormat dateFormatter = DateFormat.getTimeInstance(); g.drawString(dateFormatter.format(date), 5, 10); } // overrides Applet's stop method, not Thread's public void stop() { clockThread = null; } } 4 de 6 Elaborado por: M.C. Cecilia M. Curlango Rosas Universidad Autónoma de Baja California Facultad de Ingeniería Apuntes de Programación Orientada a Objetos I debido a la restricción de Java en cuanto a la herencia múltiple. Un ejemplo de esto sería en el caso de trabajar con applets ya que estos deben de derivarse de la clase Applet para poder trabajar. Una alternativa para este tipo de casos el de implantar la interfaz Runnable y a su vez definir un método run() apropiado para la aplicación. El Listado 4 muestra como puede hacerse esto. El ciclo de vida de un hilo La vida de un hilo inicia con el método start(). Este es el unico método que puede llamarse cuando recien se acaba de crear un hilo. Si se llama algún otro método del hilo, se provocará una excepción ya que aun no le han sido asignados recursos. Este método crear los recursos del sistema que se requieren para el hilo, lo programa para ejecución y finalmente realiza una llamada al método run() del hilo. El método run() define las operaciones que deberán realizarse por el hilo cuando éste se ejecute. Un hilo podrá entrar en estado de no ejecución cuando ocurra uno de los siguientes eventos: •Se ejecute su propio método sleep() •El hilo ejecute el método wait() para esperar que se cumpla una condición •El hilo esta bloqueado en espera de una entrada o una salida. Para detener o terminar la ejecución de un hilo puede simplemente terminarse la ejecución del método run. Tambien el recolector de basura se puede encargar de descartar un hilo una vez que ya no exista ninguna referencia a el. Métodos para el control de Hilos start() Inicia la ejecución de un hilo que acaba de crearse. stop() Detiene y mata a un hilo. sleep(int t) suspende un hilo durante t milisegundos. yield() cede su turno de ejecución a otro hilo. 5 de 6 Elaborado por: M.C. Cecilia M. Curlango Rosas Universidad Autónoma de Baja California Facultad de Ingeniería Apuntes de Programación Orientada a Objetos I resume() desbloquea un hilo y hace que este listo para ejecutarse en cuanto sea su turno. destroy() mata a un hilo. run() ejecuta las operciones que deberá realizar el hilo. 6 de 6 Elaborado por: M.C. Cecilia M. Curlango Rosas