apuntes:concurrencia
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
apuntes:concurrencia [2023/05/28 11:40] – [Streams paralelos] Santiago Faci | apuntes:concurrencia [2023/05/28 23:59] (current) – Santiago Faci | ||
---|---|---|---|
Line 63: | Line 63: | ||
Para la creación de hilos en Java disponemos de varias vías, combinando el uso de la clase Thread y el interface Runnable según nos interese: | Para la creación de hilos en Java disponemos de varias vías, combinando el uso de la clase Thread y el interface Runnable según nos interese: | ||
- | * Podemos utiliza la clase Thread heredando de ella. Es quizás la forma más cómoda porque una clase que hereda de Thread se convierte automáticamente en un hilo. Tiene una pega: esa clase ya no podrá heredera de ninguna otra, por lo que si la arquitectura de nuestra aplicación lo requiere ya no podríamos. | + | * Podemos utiliza la clase '' |
- | * Si tenemos la limitación que acabamos de comentar para el primer caso, podemos implementar el interface Runnable de forma que la clase que nosotros estamos implementado podrá además heredar sin ninguna limitación. Sólo cambia un poco la forma de trabajar directamente con la clase hilo. | + | * Si tenemos la limitación que acabamos de comentar para el primer caso, podemos implementar el interface |
* Por otra parte también podemos crear un hilo utilizando una clase anónima. No es un método que se recomiende pero en algunos casos, cuando la clase que hace de hilo no va a tener una estructura concreta es bastante cómodo hacerlo de esta manera. | * Por otra parte también podemos crear un hilo utilizando una clase anónima. No es un método que se recomiende pero en algunos casos, cuando la clase que hace de hilo no va a tener una estructura concreta es bastante cómodo hacerlo de esta manera. | ||
Line 146: | Line 146: | ||
En cualquier caso tenemos que tener siempre en cuenta las siguientes consideraciones: | En cualquier caso tenemos que tener siempre en cuenta las siguientes consideraciones: | ||
- | * Siempre se debe sobreescribir (Override) el método run() e implementar allí lo que tiene que hacer el hilo | + | * Siempre se debe sobreescribir (Override) el método |
* Podemos hacer que el hilo haga un número finito de cosas o bien que esté siempre en segundo plano (tendremos que asegurar que el método run() se ejecuta de forma continuada)(¿cómo se hace eso?) | * Podemos hacer que el hilo haga un número finito de cosas o bien que esté siempre en segundo plano (tendremos que asegurar que el método run() se ejecuta de forma continuada)(¿cómo se hace eso?) | ||
* Los problemas vienen cuando existen varios hilos. Hay que tener en cuenta que pueden compartir datos y código y encontrarse en diferentes estados de ejecución | * Los problemas vienen cuando existen varios hilos. Hay que tener en cuenta que pueden compartir datos y código y encontrarse en diferentes estados de ejecución | ||
Line 152: | Line 152: | ||
* Además, en el caso de aplicaciones multihilo, también nos puede interesar sincronizar y comunicar unos hilos con otros | * Además, en el caso de aplicaciones multihilo, también nos puede interesar sincronizar y comunicar unos hilos con otros | ||
- | También resulta interesante saber cómo detener un hilo. En este caso, la API de Java desaconsejó el método stop() que en un principio ideó para detener la ejecución. Así, hoy en día, se nos anima a que seamos nosotros quienes implementemos formas limpias de detener nuestros hilos. | + | También resulta interesante saber cómo detener un hilo. En este caso, la API de Java desaconsejó el método |
==== Sincronización de hilos ==== | ==== Sincronización de hilos ==== | ||
- | El API de Java proporciona una serie de métodos en la clase Thread para la sincronización de los hilos en una aplicación: | + | El API de Java proporciona una serie de métodos en la clase '' |
- | - //join()// | + | - '' |
- | - //Thread.sleep(int)// | + | - '' |
- | - isAlive()// | + | - '' |
- | - yield()// | + | - '' |
<code java> | <code java> | ||
Line 276: | Line 276: | ||
</ | </ | ||
- | //isAlive()// | + | '' |
===== Programación concurrente ===== | ===== Programación concurrente ===== | ||
Line 283: | Line 283: | ||
* En un entorno multi-hilo, se da una condición de carrera cuando más de un hilo intenta "al mismo tiempo" | * En un entorno multi-hilo, se da una condición de carrera cuando más de un hilo intenta "al mismo tiempo" | ||
- | * Java proporciona un mecanismo para evitar estos problemas (palabra reserva | + | * Java proporciona un mecanismo para evitar estos problemas (palabra reserva |
* Evita que más de un hilo puedan acceder a un zona de código o ejecutar un método determinado | * Evita que más de un hilo puedan acceder a un zona de código o ejecutar un método determinado | ||
Line 296: | Line 296: | ||
</ | </ | ||
- | Sin la palabra reservada | + | Sin la palabra reservada |
==== Executors y pools de hilos ==== | ==== Executors y pools de hilos ==== | ||
- | En el apartado anterior vimos como crear y lanzar hilos individualmente utilizando la clase //Thread// que Java proporcina en su API. El | + | En el apartado anterior vimos como crear y lanzar hilos individualmente utilizando la clase '' |
- | código funciona perfectamente pero realmente se vuelve complicado de desarrollar si lo que tenemos que gestionar es una gran cantidad de | + | |
- | hilos de forma simultánea. Para esos casos, Java proporciona un framework, | + | |
cualquier tarea que se ejecuta en segundo plano. | cualquier tarea que se ejecuta en segundo plano. | ||
- | Utilizando | + | Utilizando |
- | el código a realizar y asignar dicho código (una clase //Runnable// ) a un //Executor// , que se encargará de crear el hilo, lanzarlo y | + | |
- | gestionar su ejecución. | + | |
- | Veamos un ejemplo de cómo lanzar una serie de tareas en segundo plano utilizando la clase \verb ExecutorService | + | Veamos un ejemplo de cómo lanzar una serie de tareas en segundo plano utilizando la clase '' |
- | //Executors// de Java. | + | |
- | Supongamos una clase muy sencilla que implementa | + | Supongamos una clase muy sencilla que implementa |
<code java> | <code java> | ||
Line 323: | Line 319: | ||
</ | </ | ||
- | Para lanzar la tarea, o varias instancia de la misma, podemos crear un pool de hilos (en este caso dos) y pasarles las tareas al objeto | + | Para lanzar la tarea, o varias instancia de la misma, podemos crear un pool de hilos (en este caso dos) y pasarles las tareas al objeto |
- | //Executor// | + | |
- | dos hilos en cada momento. Si en algún momento se ocuparán los dos hilos, las demás tareas tendrían que esperar hasta que alguno de los dos | + | |
- | quedará libre para ejecutarse. | + | |
- | Finalmente se ejecuta el método | + | Finalmente se ejecuta el método |
- | encuentran ejecutándose con él. | + | |
- | Hay que tener en cuenta que existe también un método | + | Hay que tener en cuenta que existe también un método |
- | tareas que estaban esperando y no llegaron a ejecutarse. Se esperará que las tareas activas terminen o bien sean interrumpidas. | + | |
<code java> | <code java> | ||
Line 349: | Line 340: | ||
</ | </ | ||
- | También es posible trabajar con un //ExecutorService// que simplemente cuente con un hilo | + | También es posible trabajar con un '' |
<code java> | <code java> | ||
Line 379: | Line 370: | ||
En cualquier caso, podemos encontrarnos con dos tipos de pools de hilos: | En cualquier caso, podemos encontrarnos con dos tipos de pools de hilos: | ||
- | * **Fixed**: Se pueden crear a través de los métodos | + | * **Fixed**: Se pueden crear a través de los métodos |
- | * **Cached**: Se pueden crear a través de los métodos | + | * **Cached**: Se pueden crear a través de los métodos |
==== Callable y Future ==== | ==== Callable y Future ==== | ||
- | Hasta el momento hemos trabajado con objetos | + | Hasta el momento hemos trabajado con objetos |
- | Java proporciona también una interface llamada | + | Java proporciona también una interface llamada |
<code java> | <code java> | ||
Line 397: | Line 388: | ||
</ | </ | ||
- | Ligado a este nuevo tipo de tarea //Callable// aparece un nuevo tipo llamado | + | Ligado a este nuevo tipo de tarea '' |
- | Veamos ahora un ejemplo lanzando una tarea //Callable// y cómo se recoge su resultado: | + | Veamos ahora un ejemplo lanzando una tarea '' |
<code java> | <code java> | ||
Line 422: | Line 413: | ||
</ | </ | ||
- | Hay que tener en cuenta que la llamada al método | + | Hay que tener en cuenta que la llamada al método |
- | Además, siempre podremos cancelar el objeto | + | |
+ | Además, siempre podremos cancelar el objeto | ||
<code java> | <code java> | ||
Line 487: | Line 479: | ||
</ | </ | ||
- | En cualquier caso, el método | + | En cualquier caso, el método |
<code java> | <code java> | ||
Line 496: | Line 488: | ||
</ | </ | ||
- | Además, es posible lanzar varias tareas al mismo tiempo con el método | + | Además, es posible lanzar varias tareas al mismo tiempo con el método |
<code java> | <code java> | ||
Line 511: | Line 503: | ||
==== CompletableFuture ==== | ==== CompletableFuture ==== | ||
- | Proporciona una API más completa que la que hay para la clase //Future//. | + | Proporciona una API más completa que la que hay para la clase '' |
* Lanzar una tarea en segundo plano de forma asíncrona y ejecutar un método al finalizar ésta (a través de la llamada a un método callback) | * Lanzar una tarea en segundo plano de forma asíncrona y ejecutar un método al finalizar ésta (a través de la llamada a un método callback) | ||
Line 566: | Line 558: | ||
==== CyclicBarrier ==== | ==== CyclicBarrier ==== | ||
- | Similar a CountDownLatch pero reutilizable | + | Similar a '' |
Se utiliza para que los hilos se esperen los unos a los otros antes de realizar alguna tarea concreta | Se utiliza para que los hilos se esperen los unos a los otros antes de realizar alguna tarea concreta | ||
Line 595: | Line 587: | ||
} | } | ||
</ | </ | ||
+ | |||
==== Colecciones sincronizadas ==== | ==== Colecciones sincronizadas ==== | ||
- | Son lo que se conocen como colecciones thread-safe, | + | Son lo que se conocen como colecciones |
+ | |||
+ | En la clase '' | ||
- | En la clase Collection hay una serie de métodos estáticos que devuelven instancia de colecciones sincronizadas. Por ejemplo: | ||
* synchronizedList() | * synchronizedList() | ||
* synchronizedMap() | * synchronizedMap() | ||
* synchronizedSet() | * synchronizedSet() | ||
- | Además, existe alguna colección ya sincronizada como //Vector// (similar a //ArrayList//) y //HashTable// (similar a //HashMap//) | + | Además, existe alguna colección ya sincronizada como '' |
==== Objetos atómicos ==== | ==== Objetos atómicos ==== | ||
Line 610: | Line 604: | ||
Los objetos atómicos son estructuras Java que sirven para representar valores y realizar operaciones de forma atómica para algunos tipos de datos. | Los objetos atómicos son estructuras Java que sirven para representar valores y realizar operaciones de forma atómica para algunos tipos de datos. | ||
- | //AtomicInt//, //AtomicLong// | + | '' |
- | Por poner algún ejemplo, | + | Por poner algún ejemplo, |
- | * get() | + | * '' |
- | * compareAndSet(valorComparacion, | + | * '' |
- | * addAndGet(valor) | + | * '' |
- | * getAndIncrement() | + | * '' |
- | * incrementAndGet() | + | * '' |
- | * decrementAndGet() | + | * '' |
- | * getAndDecrement() | + | * '' |
Line 644: | Line 638: | ||
< | < | ||
- | {{ parallel_sequential.png }} | + | {{ parallel-sequential.png }} |
- | < | + | < |
+ | En los streams paralelos, se procesan los elementos de forma paralela por segmentos | ||
+ | <code java> | ||
+ | List< | ||
+ | // TODO Poblar la lista de ciudades | ||
+ | cities.parallelStream() | ||
+ | .forEach(System.out:: | ||
+ | </ | ||
+ | |||
+ | Puede mejorar el rendimiento en algunos casos, ya que permite que la aplicación realice algunos cálculos (matemáticos en este caso) de forma paralela, aprovechando mucho más los recursos de la máquina | ||
+ | |||
+ | <code java> | ||
+ | long count = Stream.iterate(0, | ||
+ | .limit(500000) | ||
+ | .parallel() | ||
+ | .filter(Main:: | ||
+ | .count(); | ||
+ | System.out.println(" | ||
+ | </ | ||
==== Locks ==== | ==== Locks ==== | ||
- | Es otro mecanismo para la sincronización de hilos parecido a como hace //synchronized// | + | Es otro mecanismo para la sincronización de hilos parecido a como hace '' |
- | Es algo más flexible que synchronized, | + | |
- | //Lock// es un interface que tiene varias opciones para implementar. Veremos un ejemplo con //ReentrantLock// | + | Es algo más flexible que '' |
+ | |||
+ | '' | ||
<code java> | <code java> | ||
Line 665: | Line 679: | ||
</ | </ | ||
- | Podemos encapsular la operación de bloqueo (lock) para evitar que se produzcan deadlocks (esperar indefinidamente un recurso) utilizando el método | + | Podemos encapsular la operación de bloqueo (lock) para evitar que se produzcan deadlocks (esperar indefinidamente un recurso) utilizando el método |
<code java> | <code java> | ||
Line 681: | Line 695: | ||
Patrón de diseño por el cual un objeto, llamada sujeto, mantiene a otros objetos, llamados observadores, | Patrón de diseño por el cual un objeto, llamada sujeto, mantiene a otros objetos, llamados observadores, | ||
- | Hasta Java 9, se proporcionaba una serie de clases que permitían definir una solución para este Patrón. A partir de entonces se recomienda el uso de //PropertyChangeListener// para dicha implementación. | + | Hasta Java 9, se proporcionaba una serie de clases que permitían definir una solución para este Patrón. A partir de entonces se recomienda el uso de '' |
=== Clase Observable === | === Clase Observable === |
apuntes/concurrencia.1685274052.txt.gz · Last modified: 2023/05/28 11:40 by Santiago Faci