Concurrencia en Java



Documentos relacionados
CONCURRENCIA EN JAVA. Diseño de Sistemas Operativos Avanzados 2000/2001. Pedro Pablo Gómez Martín

Federico Peinado

Programación Orientada a Eventos

Java nos ofrece la clase Thread y la interfaz Runable que permiten que varios procesos estén funcionando de forma concurrente.

1 HILOS (THREADS) EN JAVA

Java y JVM: programación concurrente

Benemérita Universidad Autónoma del Estado de Puebla

Concurrencia. Primitivas IPC con bloqueo

Uso de excepciones en Java

Object 1. Threads en Java

Curso de Java POO: Programación orientada a objetos

MONITORES EN JAVA. Antonio Tomeu Control de la Concurrencia en Java: API Estándar

TEMA 5: Control de la Concurrencia en Java (API Estándar)

un programa concurrente

Concurrencia en Java

Modelo de Objetos Distribuidos

Benemérita Universidad Autónoma del Estado de Puebla

Java: Programación Multithread

Threads. La plataforma JAVA soporta programas multhreading a través del lenguaje, de librerías y del sistema de ejecución. Dos.

Programación Orientada a Objetos con Java

EXCEPCIONES EN JAVA. Las sentencias que tratan las excepciones son try y catch. La sintaxis es:

Programación Concurrente en Java

Excepciones. Gonzalo Méndez - Dpto. Ingeniería de Software e Inteligencia Artificial. Excepciones

8. Sentencia return y métodos

Hebras y Sincronización en Java

Transacciones y bloqueos en SQL-Server

GESTIÓN DE EXCEPCIONES EN JAVA. CAPTURA CON BLOQUES TRY CATCH Y FINALLY. EJEMPLOS RESUELTOS. (CU00927C)

Definición de clases: Herencia, polimorfismo, ligadura dinámica

Hilos en Java. Crear un Hilo. Detener un hilo. Fuente:

Concurrencia. Bibliografía: Introducción a los Sistemas de Bases de Datos Date, C.J.

RESUMEN DE CONCEPTOS BASICOS DE PROGRAMACION JAVA

Introducción a la programación orientada a objetos

POLIMORFISMO "una interfaz, múltiples métodos".

El lenguaje de programación Java

CDI Exclusión mutua a nivel alto. conceptos

Lenguajes de Programación Curso Práctica 4. Herencia. Utilización de interfaces y clases abstractas. 1. Interfaces Clases abstractas 2

PROGRAMACIÓN ORIENTADA A OBJETOS Master de Computación. II MODELOS y HERRAMIENTAS UML. II.2 UML: Modelado de casos de uso

Receta general para resolver problemas de sincronización con semáforos

Java Inicial (20 horas)

Repaso de las características más importantes de la programación Java y su adaptación a Android

Programación Orientada a Objetos en Java

Programación orientada a objetos

Herramientas Concurrentes en JAVA

Programación Orientada a Objetos. Java: Excepciones

PROGRAMACIÓN EN JAVA

Asignación de Procesadores

MANUAL COPIAS DE SEGURIDAD

Solución al Examen de Prácticas de Programación (Ingeniería Informática)

EXAMEN FINAL Metodología y Programación Orientada a Objetos. Curso Cuatrimestre de otoño. 17 de Enero de 2011

class Nombre_Clase extends Nombre_SuperClase { cuerpo de la clase extendida }

Manual del Protocolo XML-RPC de Mensajería Negocios

Instalación. Interfaz gráfico. Programación de Backups. Anexo I: Gestión de la seguridad. Manual de Usuario de Backup Online 1/21.

Sistemas de archivos distribuidos. Alvaro Ospina Sanjuan

Concurrencia en.net David Jesús Horat Flotats

Prof. Dr. Paul Bustamante

Concurrencia: deberes. Concurrencia: Exclusión Mutua y Sincronización. Concurrencia. Dificultades con la Concurrencia

2. Estructura de un programa en Java

App para realizar consultas al Sistema de Información Estadística de Castilla y León

3.9 Patrón Distributed callback

Programación Concurrente en Java

CONTRATAS Y SUBCONTRATAS NOTAS

Patrones para persistencia (I) Ingeniería del Software II

Modulo 1 El lenguaje Java

Universidad de Cantabria

Mensajes. Interbloqueo

Capítulo 1 Introducción a la Computación

Si bien Pascal-FC no trae algunas de las características de Pascal como:

INTERRUPCIONES. La comunicación asíncrona de los sistemas periféricos con la CPU, en ambos sentidos, se puede establecer de dos maneras fundamentales:

Tema 4. Gestión de entrada/salida

Entorno de Ejecución del Procesador Intel Pentium

Intermediación ORDENES ENLAZADAS. Características y Propiedades

Concurrencia en Android LSUB, GYSC, URJC

Multitarea en Java. Rafa Caballero - UCM

Arquitectura de sistema de alta disponibilidad

Workflow, BPM y Java Resumen de la presentación de Tom Baeyens

Introducción a la Programación Orientada a Objetos

A continuación resolveremos parte de estas dudas, las no resueltas las trataremos adelante

Oficina Online. Manual del administrador

INDICE. 1. Introducción El panel Entities view El panel grafico Barra de botones Botones de Behavior...

Práctica 5. Curso

PROGRAMACIÓN PÁGINAS WEB CON PHP

Estructuras de Sistemas Operativos

Proxy Introducción

Programación en Java. Programación en OO

Unidad II: Administración de Procesos y del procesador

Capítulo 5 Programación del algoritmo en LabVIEW

Primera Escuela de la Red Temática SVO. Madrid, Noviembre, 2006 JAVA BÁSICO. Raúl Gutiérrez Sánchez LAEFF - INTA raul@laeff.inta.

Gestión de la Configuración

Realización de copias de seguridad en caliente

SERVIDOR WEB PARA ACCESO EN TIEMPO REAL A INFORMACIÓN METEOROLÓGICA DISTRIBUIDA

Monitores Ing. Iván Medrano Valencia

Secretos de la Programación Concurrente

UNIDADES FUNCIONALES DEL ORDENADOR TEMA 3

4. Programación Paralela

Ejercicio 1 (3 puntos).-

SOLUCION PARCIAL TASK SCHEDULER. Task Scheduler

Programación Orientada a Objetos. Java: Excepciones

SISTEMAS OPERATIVOS AVANZADOS

Adaptación al NPGC. Introducción. NPGC.doc. Qué cambios hay en el NPGC? Telf.: Fax.:

GESTIÓN DE REDES PARTE III

Transcripción:

Concurrencia en Java Herramientas proporcionadas por Java La Máquina Virtual (JVM) Pedro Pablo Gómez Martín La clase Thread Clase principal con la que conseguir concurrencia. La llamada a su método start() ocasiona la ejecución de su método run() en una hebra independiente. Todas las hebras que se ejecutan en una misma máquina virtual comparten recursos, como por ejemplo la memoria. La implementación de hebras particulares requiere herencia y sobreescritura del método run(). 2 1

La clase Thread class MiHebra extends Thread { int cont; MiHebra(int c) { cont = c; } public void run() { while (true) { System.out.println(cont); } } public static void main(string[] args) { new MiHebra(0).start(); new MiHebra(1).start(); } } // class Posible salida 1 1 2 2 1 1 2 1... 3 El interfaz Runnable Requieren la implementación de un método run(). Se construye una nueva hebra pasando en el constructor un objeto que implemente el interfaz. La llamada al método start() de la hebra ocasiona la ejecución del método run() del objeto pasado en una nueva hebra. No requiere herencia de la clase Thread. Se pueden construir objetos que hereden de otras clases y que pueden, no obstante, ser ejecutados. 4 2

El interfaz Runnable class MiHebra implements Runnable { int cont; MiHebra(int c) { cont = c; } public void run() { while (true) { System.out.println(cont); } } public static void main(string[] args) { new Thread(new MiHebra(0)).start(); new Thread(new MiHebra(1)).start(); } } // class 5 Diferencias El uso de la clase Thread requiere utilizar herencia. Debería usarse solo cuando haya que sobreescribir algún otro método. El uso del interfaz Runnable permite que la clase herede de cualquier otra (más versátil). Sin embargo, la ejecución requiere la construcción de un objeto añadido (aquel que implementa el interfaz Runnable) además del objeto de la clase Thread. 6 3

Finalización Cuando se termina la ejecución del método run(). Cuando llega al método run() una excepción que no se captura. Cuando se llama al método stop([excepción]) de la hebra (caso particular de la anterior). Cuando se llama al método destroy() de la hebra. No está implementado. 7 Prioridades Cada hebra tiene asociada una prioridad que ayuda a la planificador a decidir qué hebra ejecutar. Existe expropiación entre hebras de igual prioridad No se garantiza que hebras de prioridades menores pasen a ejecutarse si existe alguna hebra de más prioridad que no está bloqueada. 8 4

Prioridades La prioridad de una hebra está entre MIN_PRIORITY y MAX_PRIORITY. El valor normal es NORM_PRIORITY, todas definidas como constantes en la clase Thread. La prioridad inicial de una hebra es la misma que la prioridad de la hebra que la crea. Puede modificarse en cualquier momento mediante setpriority(int) y consultarse con getpriority() 9 Control del planificador Además de las prioridades, existen tres métodos estáticos para controlar la planificación: void sleep(long milis): duerme a la hebra al menos <milis> milisegundos. void sleep(long milis, int nanos): duerme a la hebra al menos <milis> milisegundos y <nanos> nanosegundos. void yield(): cede el procesador a otra hebra, pasandose a ejecutar el planificador. Las dos sleep(...) pueden lanzar la excepción InterruptedException. 10 5

Clases y excepciones Object Thread Throwable Class... Error Exception... RuntimeException... Excepciones de usuario 11 Cerrojos Todo los objetos (incluidos los arrays) tienen un cerrojo (lock). Solo una hebra puede tener bloqueado el cerrojo de un objeto en un momento dado. Podrá bloquearlo más de una vez antes de liberarlo y solo quedará completamente libre cuando la hebra lo libere tantas veces como lo ha obtenido. Si una hebra intenta obtener un cerrojo ocupado, quedará suspendida hasta que éste se libere y pueda obtenerlo. No se puede acceder directamente a los cerrojos. 12 6

Exclusión mútua Es posible garantizar la ejecución en exclusión mútua de un método definiéndolo como synchronized. Los métodos synchronized bloquean el cerrojo del objeto actual, o del objeto Class si el método es estático. Si el cerrojo está ocupado, la hebra se suspende hasta que éste es liberado. No se ejecutarán simultáneamente dos métodos synchronized de un mismo objeto, pero sí uno que lo sea y cualquier número de otros que no. 13 Exclusión mutua Pueden sobreescribirse métodos synchronized para que no lo sean en las clases nuevas. Sin embargo sí lo seguirá siendo el método super.metodo(...). La exclusión mutua es interesante para garantizar la consistencia del estado de los objetos. Se suelen utilizar en los métodos que hacen que el objeto pase por estados transitorios que no son correctos. Si también se hacen synchronized los métodos para consultar el estado, se evita que puedan verse estados inestables del objeto. 14 7

Exclusión mutua Puede bloquearse el cerrojo de un objeto dentro de una porción de código mediante synchronized(objeto) { }. Si el cerrojo está bloqueado por una hebra diferente (ya sea porque está ejecutando un método synchronized o porque está dentro de un bloque como el anterior), la hebra actual se suspenderá. Pueden usarse estos bloques para clases sin sincronizar que no podamos modificar. Es inseguro, mejor usar herencia. 15 Señalización Los mecanismos anteriores sirven para evitar la interferencia entre hebras. Es necesario algún método de comunicación entre ellas. Todos los objetos implementan los métodos wait() y notify(). Mediante wait() se suspende la hebra actual hasta que alguna otra llame al método notify() del mismo objeto. Todos los objetos tienen una lista de hebras que están esperando que alguien llame a notify(). 16 8

Señalización Estos métodos están pensados para avisar de cambios en el estado del objeto a hebras que están esperando dichos cambios: synchronized void dowhencondition() { while(!condition) wait(); /*... */ } synchronized void changecondition() { /*...*/ notify(); } 17 Señalización Tanto el método wait() como el notify() deben ejecutarse dentro de métodos synchronized. Cuando se llama a wait() se libera el cerrojo del objeto que se tiene bloqueado y se suspende la hebra, de forma atómica. Cuando se llama a notify() se despierta una de las hebras que estaban esperando. Ésta competirá con cualquier otra por volver a obtener el cerrojo del objeto, sin tener ningún tipo de prioridad. De ahí que sea mejor usar while(!condicion) wait(); 18 9

Señalización - Métodos wait(long tiempo): espera hasta una notificación, o hasta que pasen <tiempo> milisegundos. Si es 0, la espera es infinita. wait(long tiempo, int nanos): igual, pero con precisión de nanosegundos. wait(): igual que wait(0) notify(): despierta a una única hebra de las que están esperando. notifyall(): despierta a todas las hebras. 19 Señalización - Métodos Todos los métodos anteriores son finales. Todas las variantes de wait(...) pueden lanzar la excepción InterruptedException. notify() despierta una hebra cualquiera. No se garantiza que sea la que más tiempo lleva esperando. Es solo interesante cuando se está seguro de que solo habrá una hebra esperando. Es peligroso. notifyall() despierta a todas. Es más seguro. Requiere más que nunca el uso de while() en lugar de if(!condition) wait(); 20 10

Interbloqueos La existencia de varias hebras, y el uso de la exclusión mutua puede ocasionar la aparición de interbloqueos, en el que ninguna de dos hebras puede ejecutarse porque están esperando algo de la otra. Java no controla el interbloqueo. No se preocupa de detectarlo. Es responsabilidad del diseñador de la aplicación ser cuidadoso para evitar la aparición de interbloqueos. 21 Grupos de hebras Las hebras se estructuran de forma jerárquica. Cada nodo del árbol es un objeto de la clase ThreadGroup. Cada ThreadGroup almacena un conjunto de hebras, y otro de ThreadGroup s que contiene. Se puede establecer una prioridad al grupo, que actúa como cota máxima de las prioridades de las hebras que contiene. Cuando alguna de las hebras finaliza por una excepción, se llama al método uncaughtexception(...) de su grupo. 22 11

Métodos stop( ( ) El método stop() fuerza el lanzamiento de la excepción ThreadDeath. Es subclase de Error para que no se capture en los catch(exception e) muy habituales. Es la única excepción ignorada por el objeto ThreadGroup. Mediante stop(throwable) se puede forzar el lanzamiento de cualquier otra excepción. Los dos métodos están desaconsejados (deprecated) porque pueden dejar objetos en estados inestables. 23 Otros métodos El método suspend() detiene la hebra hasta que se llama a resume() de la misma hebra. El método destroy() destruye completamente la hebra, sin liberar ninguno de los cerrojos que pudiera tener bloqueados. No está implementado. Los tres métodos están desaconsejados (deprecated) porque pueden causar la aparición de exclusión mútua. 24 12

La máquina virtual Por hebra Por JVM Pila de Frames Heap PC Área de Código (text) Tabla de constantes 25 Frames Array de variables locales Pila de operandos Referencia a la tabla de constantes Los long y double ocupan dos entradas. El resto solo una. 26 13

Llamada a métodos Las instrucciones que llaman a un método toman como parámetro la posición dentro de la tabla de constantes donde está el nombre del método. Hay cuatro instrucciones distintas para llamar, según el tipo de método (estático, de un interfaz, privados o de superclases, y normales). Todas miran las características del método para crear un nuevo frame. Además si es synchronized, la hebra pasa a competir por la obtención del cerrojo del objeto. 27 Fin de un método Existen instrucciones return para todos los tipos básicos y para referencias, que obtienen el valor a devolver de la pila de operandos. Cuando el método termina, se elimina el frame, el frame anterior pasa a ser el frame actual, y el valor devuelto se apila en la pila de operandos de dicho frame. Si no hay más frames, la hebra finaliza. Si el método que finaliza era synchronized, el cerrojo del objeto se libera. 28 14

Fin de un método Existe la instrucción athrow con la que se lanza una excepción. Si hay algún manejador de esa excepción, se trata. Si no, se finaliza el método como antes, liberando el cerrojo si el método era synchronized, y lanzando la excepción en el método anterior. Si no quedan más métodos, se finaliza la hebra, y se llama al método del grupo de la hebra uncaughtexception(...). 29 Synchronized(o) Se implementan usando dos instrucciones de la máquina virtual. Las dos esperan la referencia al objeto cuyo cerrojo se quiere manejar: monitorenter: obtiene el cerrojo, o suspende la hebra hasta que lo consiga. monitorexit: libera el cerrojo. Para un correcto funcionamiento de synchronized(o) se requiere la cooperación del compilador que debe vigilar todas las posibles salidas del bloque. 30 15

Nuevas hebras No existe una instrucción en la máquina virtual que cree nuevas hebras. Se utilizan métodos nativos. La mayoría de los métodos de la clase Thread lo son. La llamada al método start() creará un nuevo motor de ejecución independiente al del que llama al método. La implementación es específica de la plataforma y de la implementación de la máquina virtual para dicha plataforma. Tampoco hay instrucciones para wait(...), notify() o notifyall(). 31 Gestión de memoria Hay una memoria principal, compartida por todas las hebras. Cada hebra tiene su propio espacio de memoria, con copias locales de variables de la memoria global. Se requieren mecanismos para sincronizar las copias locales con la memoria principal. La especificación de la máquina virtual obliga a que se cumplan ciertas normas en las actualizaciones. 32 16

Operaciones atómicas Memoria principal read: transmite el contenido de una variable a la memoria local de una hebra. write: almacena el valor transmitido por la memoria local de una hebra en la memoria principal. lock: bloquea un cerrojo. Se ejecuta de forma sincronizada con una hebra. unlock: desbloquea un cerrojo. Se ejecuta de forma sincronizada con una hebra. 33 Operaciones atómicas Memoria local de una hebra load: recoge el valor de un read y lo copia en la memoria local. store: envía el valor de una variable de la memoria local a la memoria principal. Hebra use: transfiere el valor de una variable de la memoria local al motor de ejecución. assign: copia un valor del motor de ejecución a la memoria local de la hebra. 34 17

Operaciones atómicas Thread Memoria de trabajo load x store use assign x x x read Memoria principal x Copia maestra write Motor de ejecución 35 Operaciones atómicas La especificación de la JVM marca restricciones en el uso de las operaciones. En general, no se especifica el momento en el que debe actualizarse la memoria principal. Solo se obliga a hacer copia en los lock/unlock. En principio, todas las operaciones son de 32 bits. Las lecturas/escrituras de double y long se hacen en dos partes. Esto puede original lecturas de valores incorrectos por otras hebras, si obtienen el valor cuando solo se ha realizado una de las operaciones de escritura. 36 18

Variables volatile Si se desea forzar la escritura en memoria principal de una variable compartida, puede usarse un lock/unlock. También pueden utilizarse variables volatile. Las reglas en las operaciones atómicas para estas variables son más estrictas. Se fuerza que por cada load haya un read, y que por cada store haya un write. Se trabaja así siempre con el valor de la copia principal. No obstante puede haber problemas en long y double. 37 Bibliografía The Java Language Specification 2nd edition. The Java Virtual Machine Specification 2nd edition. The Java Programming Languaje 2nd edition. D. Lea, Concurrent Programming in Java. Design Principles and Patterns, Addison Wesley 1996. 38 19