Universidad Nacional de San Antonio Abad del Cusco Departamento Académico de Informática Programación Concurrente y Distribuida Práctica Nº 1 Programación Multihilo en Java Ing. Iván Medrano Valencia 1. OBJETIVO. • Comprender el concepto de multihilado. • Aprender a crear, manejar y destruir hilos. • Entender el ciclo de vida de un hilo. 2. BASE TEORICA COMPLEMENTARIA CONCEPTO DE HILO (Thread). Un proceso es un programa en ejecución que es localizado en la memoria por el sistema operativo. Un hilo es una ejecución o flujo de control en el espacio de direcciones de un proceso. Un proceso puede tener mas de un hilo. Todos los hilos en un proceso tienen su propio contador de programa y su propia pila para variables locales y direcciones de retorno de invocación de procedimientos. En la figura observamos cómo sobre una CPU pueden estar ejecutándose distintos procesos pesados y uno de ellos puede estar compuesto por distintos flujos de ejecución (threads o hebras o hilos). Estas threads tendrán que “disputarse” el tiempo de ejecución que el S.O. le dé al proceso en el que residen. CLASE Thread DE JAVA . • Construcción La clase Thread (hilo) tiene varios constructores. El constructor: public Thread ( String nombreHilo ) Construye un hilo cuyo nombre es nombreHilo. El constructor: Programación Concurrente y Distribuida Multihilado public Thread () Construye un hilo cuyo nombre es “Thread” concatenado con un dígito, como Thread1, Thread2, etc. • Ejecución La invocación al método start() hace que la instancia de la clase Thread inicie la ejecución del método run() como una actividad independiente. • Un Thread termina cuando su método run() se completa, ya sea retornando o bien lanzando una excepción no controlada (es decir, RuntimeException, Error, o una de sus subclases). Si se invoca start() más de una vez provoca una InvalidThreadStateException. • Prioridades. Para hacer posible la implementación de la máquina virtual de Java sobre distintas plataformas hardware y sistemas operativos, el lenguaje de programación Java no hace ninguna promesa sobre la planificación o equitatividad, y no garantizará estrictamente que los hilos progresen. Pero los hilos proporcionan métodos para el control de la prioridad que heurísticamente influyen sobre los planificadores: ¾ Cada Thread tiene una prioridad cuyo rango se extiende de Thread.MIN_PRIORITY a Thread.MAX_PRIORITY (definidos como 1 y 10 respectivamente). ¾ Por defecto, cada hilo nuevo tiene la misma prioridad que el hilo que lo creó . El hilo inicial asociado con main() por defecto tiene prioridad Thread.NORM_PRIORITY(5). ¾ La prioridad actual de cualquier hilo se puede obtener por medio del método getPriority(). ¾ La prioridad de cualquier hilo se puede cambiar dinámicamente por medio del método setPriority(). Métodos de control. Algunos métodos de control de los hilos son: ¾ sleep(). Se invoca con argumento que especifica durante cuánto tiempo el hilo que se está ejecutando debe dormir en segundos. ¾ setName(). Establece el nombre del hilo. ¾ getName(). Devuelve el nombre del hilo. ¾ isAlive(). Retorna true si el hilo se ha iniciado pero no ha terminado. Retornará true si el hilo está bloqueado de alguna forma y false si fue cancelado o terminado. ¾ join(). Hace que el hilo actual espere hasta que el hilo al que se envió el mensaje muera antes de continuar; si no se proporciona argumento o el argumento es de 0 milisegundos, se está especificando que el hilo debe esperar indefinidamente a que muera el hilo objetivo antes de que el hilo actual continúe. ¾ wait(). Cuando un hilo en ejecución llama a wait(), el hilo pasa al estado en espera, donde espera en una cola asociada al objeto específico para el cual invocó wait() 2 Programación Concurrente y Distribuida Multihilado ¾ notify(). El primer hilo de la cola de espera para un objeto en particular queda preparado cuando otro hilo asociado a ese objeto emite una llamada notify(). ¾ notifyAll(). Todos los hilos de la cola de espera para un objeto dado quedan preparados cuando otro hilo asociado a ese objeto emite una llamada notifyAll() CICLO DE VIDA DE UN HILO EN JAVA En cualquier instante un hilo puede estar en uno de los siguientes estados. Creado start() Ocurrió evento de E/S notify() notifyAll() Planificado Terminó tiempo Expropiado Preparado Activo wait() Espera evento de E/S sleep() stop() Terminado Esperando Durmiendo Muerto Bloqueado TÉCNICAS DE IMPLEMENTACION DE HILOS EN JAVA. • Por herencia public class X extends Thread {... public x() {... } public void run() {....} .... } public class Principal //--aplicación { static X x1; static X x2; public static void main(String arg[]) throws InterruptedException { 3 Programación Concurrente y Distribuida Multihilado x1 = new X(); x2 = new X(); x1.start(); x2.start(); ... } } • Por implementación de interfase import java.io.* class X implements Runnable { public X() {...} public void run() { ..... } ..... } class Principal //--aplicación { public static void main(String arg[]) throws InterruptedException { Thread x1 = new Thread(new x()); Thread x2 = new Thread(new x()); x1.start(); x2.start(); } } 3. DESARROLLO DE LA PRACTICA Veamos un ejemplo en el que una clase crea dos hilos y los lanza a ejecución. Ambos hilos imprimen una palabra pero con distintos intervalos de tiempo. La palabra a imprimir y el intervalo de tiempo son parámetros del constructor de la clase. En este ejemplo se puede apreciar cómo se entremezcla la ejecución de ambos hilos de ejecución. //--POR HERENCIA class HiloHerencia extends Thread { String palabra; //-- palabra a imprimir long pausa; public HiloHerencia (String queDecir, long tiempoPausa) { palabra = queDecir; pausa = tiempoPausa; } public void run( ) { try { for (int i=0;i<100;i++) { System.out.println (palabra+ " "); Thread.sleep(pausa); } } catch(InterruptedException e) { 4 Programación Concurrente y Distribuida Multihilado } } } //--APLICACIÓN DE HILOS POR HERENCIA public class AppHiloHerencia { public static void main(java.lang.String[] args) { HiloHerencia hilo1; HiloHerencia hilo2; hilo1=new HiloHerencia("ton",33); hilo2=new HiloHerencia("tin",100); hilo1.start(); hilo2.start(); } } //--IMPLEMENTANDO LA INTERFAZ Runnable public class HiloRunnable implements Runnable { String palabra; //--palabra a imprimir long pausa; public HiloRunnable (String queDecir,long tiempoPausa) { palabra = queDecir; pausa = tiempoPausa; } public void run( ) { try { for (int i=0;i<100;i++) { System.out.println (palabra+ " "); Thread.sleep(pausa); } } catch(InterruptedException e) { } } } //--APLICACION DE HILOS DE INTERFAZ RUNNABLE public class AppHiloRunnable { public static void main (String args[])throws InterruptedException { //--crear hilos HiloRunnable ton = new HiloRunnable ("ton",33); HiloRunnable tin = new HiloRunnable ("tin",100); Thread hilo1 = new Thread (ton); Thread hilo2 = new Thread (tin); //--ejecutar los hilos hilo1.start(); hilo2.start(); } } 5 Programación Concurrente y Distribuida Multihilado 4. CUESTIONARIO a. Demuestre la utilización de los métodos join(), setPriority(), getPriority, setName(), getName(), stop(), isAlive(); 5. TRABAJO. a. Escriba un programa en java que muestre un recuadro en el que varias pelotas estén en movimiento. Cuando una pelota llegue al final del recuadro deberá moverse en la dirección opuesta. 6. BIBLIOGRAFÍA. • Doug Lea • Deitel & Deitel • Ken Arnold James Goslin David Holmes “Programación Concurrente en Java” 2da. Edición. Addison Wesley 2001. “JAVA How to Program” 3ra. Edición Prentice Hall 1999. “El Lenguaje de Programación JAVA”. 3ra. Edición. Addison Wesley 2001 Cusco, enero de 2008 6