Descarga la aplicación para disfrutar aún más
Vista previa del material en texto
CLASE 15 – 2.019 MODELO DE DESARROLLO DE PROGRAMAS Y PROGRAMACION CONCURRENTE FAC.DE INGENIERIA - UNJu INTERFAZ RUNNABLE IMPLEMENTACIÓN DE HILOS USANDO LA INTERFAZ RUNNABLE 1 interfaz solo puede contener mét.abstr.y/o variables estáticas y finales (constantes). Las clases pueden implementar mét.y contener variables q no sean constantes. 1 interfaz no puede implementar cualquier método. 1clase q implem.1interfaz debe implementar todos los mét.definidos en esa interfaz. 1 interfaz tiene la posibilidad d poder extenderse de otras interf.y, al contrario q las clases, puede extenderse d múltiples interf.,1 interfaz no puede ser instanciada con el operador new. Es la técn+adecuada p/la creación de aplicac.multitarea en lugar d la extens.de la clase Thread. Acciones: o Implementar el método run() de la interfaz Runnable. o Creación y ejecución de tareas. IMPLEMENTACIÓN DE HILOS USANDO LA INTERFAZ RUNNABLE La interfaz Runnable debe ser implement.x cualquier clase cuyas instancias sean ejecutadas x 1 hilo. Dicha clase debe implementar el mét.run(). La implementación de la interfaz Runnable es la forma + habitual de crear tareas, ya q proporciona al desarrollador 1forma p/agrupar el trabajo de infraestructura de la clase. La interfaz establece el trabajo a realizar y la clase o clases q la implementan, indican cómo realizar ese trabajo, se puede construir 1hilo sobre cualquier objeto q implemente la interfaz Runnable. P/implementar esta interfaz, 1clase solo tiene q implementar el método run(). Dentro del run() se define el código q constituye el nuevo hilo. Después d haberse creado 1clase q implemente la interfaz Runnable s requiere crear1 objeto del tipo Thread dentro de esa clase, usando cualquiera de los constructores de Thread. IMPLEMENT.DE HILOS USANDO LA INTERFAZ RUNNABLE - ESQUEMA // crear una clase con hilos public class MiClase implements Runnable { Thread unHilo; MiClase() { unHilo = new Thread(); } public void run() { if (unHilo != null) { //cuerpo del hilo } } } La sig.forma gral.crea el hilo e inicia su ejecución en la clase q usa a MiClase: MiClase miHilo = new MiClase (); new Thread (miHilo).start(); IMPLEMENTACIÓN DEL MÉTODO RUN() public class TareaRb implements Runnable {public void run() {for (int i=1; i<=100; i++) {System.out.println("Nombre " + Thread.currentThread().getName()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } La interfaz Runnable incluye 1único mét.run() con las acciones a realizar x las tareas. Al codificar este mét.mediante la implementación d la interfaz Runnable permite a la clase heredar al mismo tiempo la funcionalidad de alguna otra clase existente. Código d1clase p/la impresión d los nombres d los thread implement.la interf. Runnable: Al no heredar de Thread, no dispone de 1 constructor al q pasarle el nombre de la tarea; lo q se debe analizar es xq el método getName() devuelve el nombre de la tarea en ejecución. La respuesta es q la llamada a currentThread() no devuelve 1objeto TareaRb sino 1 objeto de la clase Thread q representa la tarea en ejecución. CREACIÓN Y EJECUCIÓN DE TAREAS public class Principal {public static void main (String [] args) //S crea 1único obj. tarearb q se comparte en c/thread {TareaRb t = new TareaRb(); // Las tareas son instancias de la clase Thread Thread t1 = new Thread(t,"pepe"); Thread t2 = new Thread(t,"ana"); Thread t3 = new Thread(t,"juan"); // Los Threads se ponen en ejecución t1.start(); t2.start(); t3.start(); } } Toda tarea es 1thread o sea q habrá q crear tantos objetos d la clase Thread como tareas se quieran poner en ejecución, el tema es q el código asociado a esas tareas debe ser el q está definido en el mét.run() d la clase q implem.a Runnable(). P/crear objetos Thread con estas carácter., s debe usar alguno d los sig.constructores d la clase Thread: Thread(Runnable obj) Thread (Runnable obj, String nombre) En ambos casos, la creación y ejecución de las tareas en el ej.de la impresión de nombres quedaría : EJEMPLOS SIN HILOS, CON THREAD Y CON INTERFAZ RUNNABLE Se simula el proceso de cobro de un supermercado; donde: • Los clientes adquieren productos • 1cajera cobra los productos, pasándolos 1 a 1 x el escáner de la caja registradora. La cajera debe procesar la compra cliente a cliente, 1ro. le cobra al cliente 1, luego al cliente 2 y así sucesivamente. Se define 1 clase “Cajera” y una clase “Cliente” el cual tendrá un “array de enteros” q representa los productos q se compraron y el tiempo q la cajera tarda en pasar el producto x el escáner. X ej. si se tiene 1 array con [1,3,5] significa q el cliente ha comprado 3 productos y q la cajera tarda en procesar al producto 1 ‘1 segundo’, al producto 2 ‘3 segundos’ y al producto 3 ‘5 segundos’, con lo cual se tarda en cobrar al cliente x toda su compra ‘9 segundos’. CLASE “CAJERA.JAVA“ public class Cajera { private String nombre; public Cajera(String nombre) { super(); this.nombre = nombre; } public void procesarCompra (Cliente cliente, long timeStamp) { System.out.println("La cajera " + this.nombre + " COMIENZA A PROCESAR LA COMPRA DEL CLIENTE "+ cliente.getNombre() + " EN EL TIEMPO: “ + (System.currentTimeMillis() - timeStamp) / 1000 + "seg"); for (int i = 0; i < cliente.getCarroCompra().length; i++) { this.esperarXsegundos(cliente.getCarroCompra()[i]); System.out.println("Procesado el producto " + (i + 1) + " ->Tiempo: " + (System.currentTimeMillis() - timeStamp) / 1000 + "seg"); } System.out.println("La cajera " + this.nombre + " HA TERMINADO DE PROCESAR " + cliente.getNombre() + " EN EL TIEMPO: " + (System.currentTimeMillis() - timeStamp) / 1000 + "seg"); } private void esperarXsegundos (int segundos) { try { Thread.sleep(segundos * 1000); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } } } CLASE “CLIENTE.JAVA” public class Cliente { private String nombre; private int[] carroCompra; public Cliente(String nombre, int[] carroCompra) { super(); this.nombre = nombre; this.carroCompra = carroCompra; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } public int[] getCarroCompra() { return carroCompra; } public void setCarroCompra(int[] carroCompra) { this.carroCompra = carroCompra; } } Si se ejecuta este programa con 2 Clientes y 1solo proceso (q es lo q se suele hacer normalmente), se procesa 1ro.la compra del Cliente 1 y después la del Cliente 2, con lo cual se tarda el tiempo del Cliente 1 + Cliente 2. CUIDADO: Aunq se haya puesto 2 objetos de la clase Cajera (cajera1 y cajera2) no significa tener 2cajeras independientes, lo q se afirma es q dentro del mismo hilo se ejecutan 1ro.los mét.d la cajera1 y después los mét.d la cajera2. A nivel de procesam.es como tener 1 sola cajera. A continuac.se implementa el mét. Main para lanzar el programa. CLASE “MAIN.JAVA“ public class Main { public static void main(String[] args) { Cliente cliente1 = new Cliente("Cliente 1", new int[] { 2, 2, 1, 5, 2, 3 }); Cliente cliente2 = new Cliente("Cliente 2", new int[] { 1, 3, 5, 1, 1 }); Cajera cajera1 = new Cajera("Cajera 1"); Cajera cajera2 = new Cajera("Cajera 2"); // Tiempo inicial de referencia long initialTime = System.currentTimeMillis(); cajera1.procesarCompra(cliente1, initialTime); cajera2.procesarCompra(cliente2, initialTime); } } Si s ejecuta este ej.se observa cómo s procesa 1ro.la compra del cliente 1 y después la compra del cliente 2 tardando en procesar ambas compras un tiempo de 26 seg. CLASE “CAJERATHREAD.JAVA“ public class CajeraThread extends Thread { private String nombre; private Cliente cliente; private long initialTime; // Constructor, getter & setter public CajeraThread(String nombre, Cliente cliente, long initialTime) { super(); this.nombre = nombre; this.cliente = cliente;this.initialTime = initialTime; } Se pueden procesar 2clientes a la vez si hubiese 2cajeras y se asigna 1a c/cliente. P/ello se modifica la clase “Cajera.java” haciendo q herede de la clase Thread p/heredar y sobre-escribiendo algunos de sus métodos. 1ro.se codifica la clase “CajeraThread.java” y después se explican sus características. La clase “CajeraThread” hereda de la clase Thread CLASE “CAJERATHREAD.JAVA“@Override public void run() { System.out.println("La cajera “+this.nombre+ " COMIENZA A PROCESAR LA COMPRA DEL CLIENTE " +this.cliente.getNombre()+" EN EL TIEMPO: "+(System.currentTimeMillis() - this.initialTime)/1000+"seg"); for (int i = 0; i < this.cliente.getCarroCompra().length; i++) { this.esperarXsegundos(cliente.getCarroCompra()[i]); System.out.println("Procesado el producto " + (i + 1) + " del cliente " + this.cliente.getNombre() + "->Tiempo: " + (System.currentTimeMillis() - this.initialTime) / 1000 + "seg"); } System.out.println("La cajera "+this.nombre+" TERMINO DE PROCESAR"+this.cliente.getNombre() + " EN EL TIEMPO: " + (System.currentTimeMillis() - this.initialTime) / 1000 + "seg"); } private void esperarXsegundos(int segundos) { try { Thread.sleep(segundos * 1000); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } } } Es imprescindible sobre-escribir el método “run()” (de ahí la etiqueta @Override) , ya q es un método q está en la clase Runnable y la clase Thread Implementa esa Interfaz, y xq en él se codifica la funcionalidad q se ejecuta en 1hilo; es decir, q lo q se programe en el mét.“run()” se va a ejecutar d forma secuencial en 1 hilo. En la clase “CajeraThread” se pueden sobre-escribir más métodos p/q hagan acciones sobre el hilo o thread como x ej., parar el thread, ponerlo en reposo, etc CLASE “MAINTHREAD.JAVA“public class MainThread { public static void main(String[] args) { Cliente cliente1 = new Cliente("Cliente 1", new int[] { 2, 2, 1, 5, 2, 3 }); Cliente cliente2 = new Cliente("Cliente 2", new int[] { 1, 3, 5, 1, 1 }); long initialTime = System.currentTimeMillis(); // Tiempo inicial de referencia CajeraThread cajera1 = new CajeraThread("Cajera 1", cliente1, initialTime); CajeraThread cajera2 = new CajeraThread("Cajera 2", cliente2, initialTime); cajera1.start(); cajera2.start(); } } El mét.Main de la clase “MainThread.java” procesa las compras de los clientes de forma paralela e independiente, y tarda solo 15 segundos en terminar su ejecución. CLASE “MAINTHREAD.JAVA“ public class MainRunnable implements Runnable{ private Cliente cliente; private Cajera cajera; private long initialTime; public MainRunnable (Cliente cliente, Cajera cajera, long initialTime){ this.cajera = cajera; this.cliente = cliente; this.initialTime = initialTime;} public static void main(String[] args) { Cliente cliente1 = new Cliente("Cliente 1", new int[] { 2, 2, 1, 5, 2, 3 }); Cliente cliente2 = new Cliente("Cliente 2", new int[] { 1, 3, 5, 1, 1 }); Cajera cajera1 = new Cajera("Cajera 1"); Cajera cajera2 = new Cajera("Cajera 2"); // Tiempo inicial de referencia long initialTime = System.currentTimeMillis(); Runnable proceso1 = new MainRunnable(cliente1, cajera1, initialTime); Runnable proceso2 = new MainRunnable(cliente2, cajera2, initialTime); new Thread(proceso1).start(); new Thread(proceso2).start(); } @Override public void run() { this.cajera.procesarCompra(this.cliente, this.initialTime); } } Otra forma es implementar la Interfaz “Runnable”. En este caso no se dispone ni se podrá sobre-escribir los mét. d la clase Thread ya q no s van a usar y solo s va a tener q sobre- escribir el mét.“run()“. Solo es necesario implementar el mét. “run()” p/q los procesos implement. en ese mét.s ejecuten en 1hilo diferente. En este ej. se utiliza objetos de las clases “Cliente.java” y “Cajera.java” p/ implementar la multitarea. • García de Jalón J, Rodríguez J, Mingo I, Imaz A, Brazalez A, Larzabal A, Calleja J y García J. 2.000. Aprenda Java como si estuviera en primero. • Página web consultada, accedidas en Septiembre de 2.018: o http://jarroba.com/multitarea-e-hilos-en-java-con-ejemplos-thread- runnable/ • Sánchez Jorge. 2.004. Java2 incluye Swing, Threads, programación en red, Javabeans, JDBC y JSP / Servlets. BIBLIOGRAFÍA RECOMENDADA
Compartir