View
224
Download
1
Category
Preview:
Citation preview
Multitarea en Java
Rafa Caballero - UCM
Programa Monoproceso (monotarea)
En cada momento hay una única instrucción ejecutándose
Se dice que el programa es monotarea, o monoproceso o monohebra (o single threading).
Rafa Caballero Rafa Caballero -- UCMUCM
Programa multiproceso
En algún punto el programa se divide en varios procesos (threads) que se ejecutan (aparentemente) de manera simultánea
Programa multiproceso, multitarea, multihebra (o multithreading)
Rafa Caballero Rafa Caballero -- UCMUCM
¿Para qué?
Programas que tengan que realizar varias tareas de manera simultánea
Programas en los que la ejecución de una parte requiera tiempo y no deba detener el resto del programa
Rafa Caballero Rafa Caballero -- UCMUCM
¿Para qué ? Ejemplo 1
Programa que controla sensores en una fábrica: Los procesos que se encargan de controlar sensoresdiferentes son independientes y los sensores deben controlarse de manera simultánea
Programa
Temperatura
Presión Tiempo
Combustible
Rafa Caballero Rafa Caballero -- UCMUCM
¿Para qué? Ejemplo 2
Durante la impresión de un documento (tarea que puede tomar tiempo) el programa puede y debe continuar ejecutándose.
Rafa Caballero Rafa Caballero -- UCMUCM
Programa
Multitarea en Java
Idea: Definir clases especiales para las tareas que requieran ejecutarse en una hebra de ejecución (thread) separada
Estas clases deben incluir la función especial public void run(), equivalente a main() pero para hebras
Los objetos de la clase serán inicializados desde otra clase con el método start()
Rafa Caballero Rafa Caballero -- UCMUCM
Clase para multitarea
2 Métodos:
n Mediante herencia (extensión) de la clase java.lang.Thread
n Mediante la implementación del interfaz java.lang.Runnable
Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: extensión de Thread
El programa irá escribiendo dos sucesiones ascendentes de números simultáneamente
Una hebra por cada contador
Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: Contadores (Versión 1)class Contador extends Thread {private int inicio,fin; // valor inicial y final del contadorprivate String nombre; // nombre de la hebra
// constructor con los valores iniciales y final y el nombrepublic Contador(int desde, int hasta, String id) {inicio = desde; fin = hasta; nombre = id;
}// función principalpublic void run() {
System.out.println(nombre+ " empieza...");for (int i = inicio; i <= fin; i++) {
System.out.print (nombre+" dice: "+i + ". ");try{ sleep(10); // paramos una centesima de segundo
} catch (InterruptedException e) { e.printStackTrace(); }}
System.out.println(nombre + " acaba.");}
}Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: Contadores (Versión 1)// clase principal: esta clase inicializara las hebraspublic class principal {
static public void main(String[] args) {// al declararlas NO comienzanContador hebraA = new Contador(1, 10, "HebraA");Contador hebraB = new Contador(20, 30, "HebraB");
System.out.println("Vamos a iniciar las dos hebras");// ahora comienzanhebraA.start();hebraB.start();System.out.println("Hebras inicializadas");
// hacemos un poco de tiempo antes de despedirnosfor (int i=0; i<50000000; i++) ;System.out.println("Programa principal terminado");}
} // principalRafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: contadores
Una ejecución del programa:
Vamos a iniciar las dos hebrasHebras inicializadasHebraA empieza...HebraA dice: 1. HebraB empieza...HebraB dice: 20. HebraA dice: 2. HebraB dice: 21. HebraA dice: 3.
HebraB dice: 22. HebraA dice: 4. Programa principal terminadoHebraB dice: 23. HebraA dice: 5. HebraB dice: 24. HebraA dice: 6.
HebraB dice: 25. HebraA dice: 7. HebraB dice: 26. HebraA dice: 8. HebraB dice: 27. HebraA dice: 9. HebraB dice: 28. HebraA dice: 10. HebraB dice: 29. HebraA acaba.
HebraB dice: 30. HebraB acaba.
Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: contadores
HebraB dice: 29HebraA dice:10
HebraB acabaHebraA acaba
HebraB dice: 28HebraA dice:9
HebraB dice: 27HebraA dice:8
HebraB dice: 26HebraA dice:7
HebraB dice: 25HebraA dice:6
HebraB dice: 24HebraA dice:5
HebraB dice: 23Programa Principal TerminadoHebraA dice:4
HebraB dice: 22HebraA dice:3
HebraB dice: 21HebraA dice:2
HebraB dice: 20HebraA dice:1
Hebra B empieza…HebraA empieza…
Hebras Inicializadas
Vamos a iniciar las dos hebras
Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: Interfaz Runnable
Se utiliza generalmente cuando la clase ya hereda de otra clase y por tanto no puede heredar de Thread
class Hebra extends loquesea implements Runnable {
……}
Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: Contadores (versión 2)class Contador implements Runnable {
private int inicio,fin; // valor inicial y final del contadorprivate String nombre; // nombre de la hebra
// constructor con los valores iniciales y final y el nombrepublic Contador(int desde, int hasta, String id) {inicio = desde; fin = hasta; nombre = id;
}
public void run() {System.out.println(nombre+ " empieza...");for (int i = inicio; i <= fin; i++) {
System.out.print (nombre+" dice: "+i + ". ");try{ Thread.sleep(10); // paramos una centesima de segundo
} catch (InterruptedException e) { e.printStackTrace(); }}
System.out.println(nombre + " acaba.");}
}Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: Contadores (versión 2)// clase principal: esta clase inicializara las hebraspublic class principal {
static public void main(String[] args) {// al declararlas NO comienzanThread hebraA = new Thread (new Contador(1, 10, "HebraA"));Thread hebraB = new Thread (new Contador(20, 30, "HebraB"));
// ahora comienzanhebraA.start();hebraB.start();System.out.println("Hebras inicializadas");
// hacemos un poco de tiempo antes de despedirnosfor (int i=0; i<50000000; i++) ;System.out.println("Programa principal terminado");}
} // principal
Contador hebraA = new Contador(1, 10, "HebraA");Contador hebraB = new Contador(20, 30, "HebraB");
Rafa Caballero Rafa Caballero -- UCMUCM
Comunicación entre hebras
La forma de comunicarse consiste usualmente en compartir un mismo objeto
Generalmente el objeto se pasa como parámetro en la constructora de la clase hebra
Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: Juego para adivinar un número
ÁrbitroNúmero: 5
Jugador
4
2 7
3
Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: Juego para adivinar un número
3 Clases:n Principal: Inicializa el árbitro y lanza las hebras
de los jugadoresn Árbitro: Contiene el número a adivinar, el turno
y muestra el resultadon Jugador: Extiende Thread e incluye al árbitro.
Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: Juego para adivinar un número
public class Principal {
public static void main(String[] args) {// creamos el árbitro y los jugadores
Arbitro arbitro = new Arbitro(3); // 3 jugadores
Jugador j1 = new Jugador(1,arbitro);Jugador j2 = new Jugador(2,arbitro);Jugador j3 = new Jugador(3,arbitro);
// ponemos a los jugadores en marchaj1.start(); j2.start(); j3.start();
}}
Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: Juego para adivinar un número
class Arbitro {private int totalJugadores; // núm. de jugadoresprivate int turno; // a quién le tocaprivate int numero; // número a adivinarprivate boolean acabo; // true cuando se haya terminado el juego
public Arbitro(int nJugadores) {// constructoratotalJugadores = nJugadores;turno = 1+(int) (totalJugadores*Math.random());numero = 1+(int) (10*Math.random()); // número entre 1 y 10acabo = false;
} public int toca() { return turno; }public boolean seAcabo() { return acabo; }public synchronized void nuevaJugada(int jugador, int suNumero) {…}
}Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: Juego para adivinar un número
public synchronized void nuevaJugada(int jugador, int suNumero){
if (jugador == toca()) { // ha acertadoSystem.out.println(“Jugador”+jugador+" dice: "+suNumero);if (suNumero == numero) {
System.out.println(“Jugador “+jugador + " gana!!!");acabo = true;
} else // ha fallado. ver a quien le toca ahoraif (turno == totalJugadores) turno = 1;else turno++;
}else System.out.println(jugador+" trata de hacer trampa!");
}
Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: Juego para adivinar un número
class Jugador extends Thread {Arbitro arbitro; int identificador;
public Jugador( int elId,Arbitro elArbitro) {arbitro = elArbitro; identificador = elId;
}public void run() {
while (arbitro.seAcabo() == false) { // hasta el fin del juegoif (arbitro.toca()==identificador) { // es nuestro turno
int jugada = 1+(int) (10*Math.random());arbitro.nuevaJugada(identificador,jugada);
} // if} // while
} // run}
Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: Juego para adivinar un número
Una ejecución del programa:
Jugador 3 dice: 9
Jugador 1 dice: 2
Jugador 2 dice: 6
Jugador 3 dice: 7
Jugador 1 dice: 2
Jugador 2 dice: 5
Jugador 2 gana!!!
Rafa Caballero Rafa Caballero -- UCMUCM
Ejemplo: Juego para adivinar un número
Observaciones:
n Aunque cada hebra tenga su variable árbitro todas son referencias al mismo objeto
n Con synchronized se protegen aquellas funciones que no se quiera que se puedan interrumpir por otra hebra
Rafa Caballero Rafa Caballero -- UCMUCM
Ejercicio: Control de stock
Se sabe que a un almacén llegan piezas cada 8 horas. La cantidad de piezas oscila cada vez entre 400 y 1000
Del almacén salen cada 24 horas piezas hacia la fábrica, a un ritmo de entre 2000 y 2500 piezas (todas a la vez)
El almacén parte de 8000 piezas y tiene una capacidad máxima de 20000 piezas
Rafa Caballero Rafa Caballero -- UCMUCM
Ejercicio: Control de stock
El programa debe simular este proceso parando si:
n Llega un nuevo cargamento y ya no cabe en el almacén
n La fábrica necesita piezas pero no hay suficientes piezas en el almacén
Rafa Caballero Rafa Caballero -- UCMUCM
Ejercicio: Control de stock
Rafa Caballero Rafa Caballero -- UCMUCM
Ejercicio: Control de stock
Vamos a hacer la simulación con 4 clases:
n Retirada: Simula retirada de piezas hacia la fábrica. Además escribe el número de días transcurridos desde el comienzo
n Envío: Simula el envío de piezas al almacén
n Almacén: Simula el almacén. Tendrá funciones para atender las llegadas y las salidas de piezas. Controlará si hay algún error y mostrará mensajes con el movimiento del almacén
n Principal: Función main que pondrá en marcha la aplicación
Rafa Caballero Rafa Caballero -- UCMUCM
Ejercicio: Control de stock
Envío y Retirada heredarán de la clase Thread y compartirán el objeto tipo Almacén.
Ambas pararán cuando el Almacén indique que hay un error (bien porque no hay piezas para atender un pedido o porque no caben más piezas y hay un envío)
Rafa Caballero Rafa Caballero -- UCMUCM
Ejercicio: Control de stockPara simular el tiempo, las funciones run() de las clases Retirada y Envio incluirán sendas llamadas a sleep:
n En el caso de Retirada:try{ sleep(2400); // simulación de un día } catch (InterruptedException e) { e.printStackTrace(); }
n En el caso de Envio:try{ sleep(800); // simulación de 8 horas } catch (InterruptedException e) { e.printStackTrace(); }
De está manera habrá 3 envíos por cada retirada
Rafa Caballero Rafa Caballero -- UCMUCM
Ejercicio: Control de stock
// Estructura de la clase almacén:class Almacen {private final int maximo=20000; // capacidad del almacénprivate int stock = 8000; // núm. Piezas en el almacén. Al principio 8000private boolean hayError = false; // al principio no hay error
// Método entrada: ‘carga’ es la cantidad de piezas que llegan al almacén// si la carga + el stock superan el maximo mostrará un mensaje de error y // pondrá hayErrora true. En otro caso incrementará el stock con la ‘carga’public void entrada(int carga) { ….}
// Método salida: ‘piezas’ es la cantidad de piezas pedida por la fábrica// Si stock < piezas se mostrará un mensaje de erro y se pondrá // hayError a true. En otro caso se decrementará el stock en ‘piezas’public void salida(int piezas) { } // pedido
public boolean error() { return hayError; }}
Rafa Caballero Rafa Caballero -- UCMUCM
Ejercicio: Control de stock
…...Día 41Pedido de 2409 piezasHay 699 piezas en el almacénLlegan 586 piezasHay 1285 piezas en el almacénLlegan 404 piezasHay 1689 piezas en el almacénLlegan 462 piezasHay 2151 piezas en el almacén
Día 42Pedido de 2483 piezasNo hay piezas suficientes!
Día 1Pedido de 2179 piezasHay 5821 piezas en el almacénLlegan 744 piezasHay 6565 piezas en el almacénLlegan 580 piezasHay 7145 piezas en el almacénLlegan 624 piezasHay 7769 piezas en el almacén
Día 2Pedido de 2420 piezasHay 5349 piezas en el almacén
Rafa Caballero Rafa Caballero -- UCMUCM
Ejercicio: Control de stock
Resultados de 20 simulaciones
0
10
20
30
40
50
60
70
80
1ª 4ª 7ª 10ª 13ª 16ª 19ª
Días hastaquedarse vacío
Rafa Caballero Rafa Caballero -- UCMUCM
Ejercicio: Control de stock
Sugerencia: probar con otros valores
Por ejemplo, con 4 envíos por día se comprobará que el almacén se llena en aproximadamente 25 días
Rafa Caballero Rafa Caballero -- UCMUCM
Recommended