apuntes:concurrencia
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionLast revisionBoth sides next revision | ||
apuntes:concurrencia [2023/05/28 11:02] – [Colecciones sincronizadas] Santiago Faci | apuntes:concurrencia [2023/05/28 11:44] – [Streams paralelos] Santiago Faci | ||
---|---|---|---|
Line 36: | Line 36: | ||
Es la programación de aplicaciones en las que las tareas a ejecutar se reparten entre varios equipos diferentes (conectados en red, a los que llamaremos nodos). Juntos, estos equipos, forman lo que se conoce como un Sistema Distribuido, | Es la programación de aplicaciones en las que las tareas a ejecutar se reparten entre varios equipos diferentes (conectados en red, a los que llamaremos nodos). Juntos, estos equipos, forman lo que se conoce como un Sistema Distribuido, | ||
- | \begin{figure}[h!] | + | <figure> |
- | | + | {{ concurrencia.jpg |
- | \includegraphics[scale=0.8]{partes/ | + | <caption> |
- | \caption{Programación concurrente/paralela} | + | |
- | \end{figure} | + | |
- | \begin{figure}[h!] | + | <figure> |
- | \centering | + | {{ distribuida.jpg |
- | | + | <caption>Programación distribuida</ |
- | \caption{Programación distribuida} | + | |
- | \end{figure} | + | |
==== ¿Qué son los hilos? ==== | ==== ¿Qué son los hilos? ==== | ||
Line 57: | Line 53: | ||
=== Estados de un hilo === | === Estados de un hilo === | ||
- | + | <figure> | |
- | \begin{figure}[h!] | + | {{ estados_hilo.png |
- | | + | <caption>Estados de un hilo</ |
- | \includegraphics[scale=1.4]{partes/ | + | |
- | \caption{Estados de un hilo} | + | |
- | \end{figure} | + | |
=== Programación multihilo en Java === | === Programación multihilo en Java === | ||
Line 515: | Line 508: | ||
. . . | . . . | ||
</ | </ | ||
+ | |||
+ | ==== CompletableFuture ==== | ||
+ | |||
+ | Proporciona una API más completa que la que hay para la clase //Future//. | ||
+ | |||
+ | * 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) | ||
+ | |||
+ | <code java> | ||
+ | CompletableFuture.runAsync(() -> doSomething()) | ||
+ | .whenComplete((string, | ||
+ | </ | ||
+ | |||
+ | * Lanzar una tarea y ejecutar algo cuando ésta termina: | ||
+ | |||
+ | <code java> | ||
+ | private String doSomethingAndReturnResult() { | ||
+ | return " | ||
+ | } | ||
+ | |||
+ | CompletableFuture.supplyAsync(() -> doSomethingAndReturnResult()) | ||
+ | .thenAccept(System.out:: | ||
+ | .whenComplete((nothing, | ||
+ | </ | ||
+ | |||
==== CountDownLatch ==== | ==== CountDownLatch ==== | ||
Line 591: | Line 608: | ||
==== Objetos atómicos ==== | ==== Objetos atómicos ==== | ||
- | ==== Objetos | + | Los objetos atómicos son estructuras Java que sirven para representar valores y realizar operaciones de forma atómica para algunos tipos de datos. |
+ | |||
+ | // | ||
+ | |||
+ | Por poner algún ejemplo, // | ||
+ | * get() | ||
+ | * compareAndSet(valorComparacion, | ||
+ | * addAndGet(valor) | ||
+ | * getAndIncrement() | ||
+ | * incrementAndGet() | ||
+ | * decrementAndGet() | ||
+ | * getAndDecrement() | ||
+ | |||
+ | |||
+ | ==== Variables | ||
+ | |||
+ | Es una palabra reservada que sirve para indicarle a Java que la variable debe ser escriba en memoria principal de forma inmediata cuando vea modificado su valor, para evitar que otros hilos que la utilicen puedan tener un valor diferente no actualizado | ||
+ | |||
+ | * private volatile int valor; | ||
+ | |||
+ | Hay que tener en cuenta que no siempre será suficiente y sólo servirá para situaciones donde un hilo esté leyendo alguna variable que otro hilo modifique. No nos ayudará a evitar las condiciones de carrera que hemos visto anteriormente. En esos casos necesitaremos, | ||
+ | |||
+ | < | ||
+ | {{ volatile.png }} | ||
+ | < | ||
==== Streams paralelos ==== | ==== Streams paralelos ==== | ||
+ | |||
+ | La ejecución en paralelo significa que se ejecutan fragmentos de código de una aplicación al mismo tiempo. | ||
+ | |||
+ | Hay que tener en cuenta que, en determinadas circunstancias, | ||
+ | |||
+ | En otras circustancias puede interesar puesto que la aplicación aprovecha mucho más los recursos de la máquina al forzar a ésta a ejecutar algunas operaciones de forma simultánea | ||
+ | |||
+ | < | ||
+ | {{ 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 // | ||
+ | Es algo más flexible que synchronized, | ||
+ | //Lock// es un interface que tiene varias opciones para implementar. Veremos un ejemplo con // | ||
+ | |||
+ | <code java> | ||
+ | Lock lock = new ReentrantLock(); | ||
+ | lock.lock(); | ||
+ | try { | ||
+ | // Aqui se accede al recurso/ | ||
+ | } finally { | ||
+ | lock.unlock(); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Podemos encapsular la operación de bloqueo (lock) para evitar que se produzcan deadlocks (esperar indefinidamente un recurso) utilizando el método //tryLock// indicando el tiempo que el hilo esperará por el recurso | ||
+ | |||
+ | <code java> | ||
+ | boolean isLocked = lock.tryLock(2, | ||
+ | if (isLocked) { | ||
+ | try { | ||
+ | // Aqui se accede al recurso/ | ||
+ | } finally { | ||
+ | lock.unlock(); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
==== Patrón Observer ==== | ==== Patrón Observer ==== | ||
+ | |||
+ | 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 // | ||
+ | |||
+ | === Clase Observable === | ||
+ | |||
+ | <code java> | ||
+ | public class Product { | ||
+ | private String nombre; | ||
+ | . . . | ||
+ | private PropertyChangeSupport change; | ||
+ | | ||
+ | @Override | ||
+ | public void addPropertyChangeListener(PropertyChangeListener listener) { | ||
+ | change.addPropertyChangeListener(listener); | ||
+ | } | ||
+ | | ||
+ | @Override | ||
+ | public void removePropertyChangeListener(PropertyChangeListener listener) { | ||
+ | change.removePropertyChangeListener(listener); | ||
+ | } | ||
+ | | ||
+ | public void decreaseStock(int quantity) { | ||
+ | change.firePropertyChange(" | ||
+ | stock -= quantity; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | === La clase Observer === | ||
+ | |||
+ | <code java> | ||
+ | public class Provider implements PropertyChangeListener { | ||
+ | private String name; | ||
+ | . . . | ||
+ | @Override | ||
+ | public void propertyChange(PropertyChangeEvent event) { | ||
+ | if (event.getPropertyName().equals(" | ||
+ | System.out.println(" | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Y el programa principal para ver el ejemplo funcionar: | ||
+ | |||
+ | <code java> | ||
+ | public static void main(String args[]) { | ||
+ | Product product = new Product(); | ||
+ | . . . | ||
+ | Customer customer = new Customer(); | ||
+ | . . . | ||
+ | product.addPropertyChangeListener(customer); | ||
+ | product.setStock(10); | ||
+ | } | ||
+ | </ | ||
---- | ---- |
apuntes/concurrencia.txt · Last modified: 2023/05/28 23:59 by Santiago Faci