48
1 TEMA 6: API Java para Concurrencia de Alto Nivel © Antonio Tomeu API Java para Concurrencia de Alto Nivel CONTENIDO API Java 5 de Control de la Concurrencia Clases para Gestión de Variables Atómicas Clase java.concurrent.util.concurrent.Semaphore Clase java.concurrent.util.concurrent.CyclicBarrier El API java.concurrent.util.concurrent.locks y la interfaz Condition Colas Contenedoras Sincronizados Pool de Threads: Concepto, utilidad y utilización BIBLIOGRAFÍA RECOMENDADA: [Göe06] Göetz et al. Java Concurrency in Practice, 2006. [Oaks04] Oaks & Wong. Java Threads. O`Reilly, 2004.

Diapositivas del Tema 6

Embed Size (px)

Citation preview

Page 1: Diapositivas del Tema 6

1

TEMA 6: API Java para Concurrencia de Alto Nivel

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

CONTENIDOAPI Java 5 de Control de la ConcurrenciaClases para Gestión de Variables AtómicasClase java.concurrent.util.concurrent.SemaphoreClase java.concurrent.util.concurrent.CyclicBarrierEl API java.concurrent.util.concurrent.locks y la interfaz ConditionColas Contenedoras SincronizadosPool de Threads:

Concepto, utilidad y utilización

BIBLIOGRAFÍA RECOMENDADA:[Göe06] Göetz et al. Java Concurrency in Practice, 2006.[Oaks04] Oaks & Wong. Java Threads. O`Reilly, 2004.

Page 2: Diapositivas del Tema 6

2

Disponible a partir de Java 5Mejoras respecto a los mecanismos previos de control de la concurrencia• Generan menos sobrecarga en tiempo de ejecución• Permiten controlar la e.m. y la sincronización a un

nivel más fino• Soporta primitivas clásicas como los semáforos o las

variables de condición en monitores• Añade nuevas primitivas y gestión de hilos mediante

pools.

Generalidades

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 3: Diapositivas del Tema 6

3

Disponible en los paquetes:java.util.concurrentjava.util.concurrent.atomicjava.util.concurrent.locks

Cierres para control de e.m.Semáforos, BarrerasColecciones (clases contenedoras) concurrentes de acceso sincronizadoVariables atómicas

¿Qué paquetes usar?

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 4: Diapositivas del Tema 6

4

El API java.util.concurrent.atomic

Conjunto de clases que soportan programación concurrente segura sobre variables simples tratadas de forma atómicaClases: AtomicBoolean,AtomicInteger, AtomicIntegerArray,AtomicLong,AtomicLongArray,AtomicReference<V>, etc.OJO: No todos los métodos del API de estas clases soportan concurrencia segura. Sólo aquellos en los que se indica que la operación se realiza de forma atómica

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 5: Diapositivas del Tema 6

5

import java.util.concurrent.atomic.*;

class Hilo extends Thread{

AtomicInteger cont = null; //el contador es entero “atómico”

public Hilo(AtomicInteger c) {this.cont = c;}public void run(){//se incrementa cont, retornando el valor previoint valor = this.cont.incrementAndGet();System.out.println(valor);}

}

public class prueba_var_atomic {

public static void main(String[] args) {

AtomicInteger cnt = new AtomicInteger(0);

for(int i=0; i<100; i++){Hilo h = new Hilo(cnt);h.start();

}}

} © Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 6: Diapositivas del Tema 6

6

Escribir una condición de carrera usando objetos AtomicInteger y verificar que se preserva la e.m.

EJERCICIO

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 7: Diapositivas del Tema 6

7

Permite disponer de semáforos de conteo de semántica mínima igual a la estándar de Djikstra, o aumentada.Métodos principales:Semaphore (long permits)acquire(), acquire(int permits)release(), release (int permits)tryAcquire(); varias versionesavalaiblePermits()

La clase java.util.concurrent.Semaphore

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 8: Diapositivas del Tema 6

8

import java.util.concurrent.*;

public class Bloqueo_Semaforo {

public static void main(String[] args)throws InterruptedException{Semaphore sem = new Semaphore (2);sem.acquire(2);System.out.println("Semaforo actualizado a valor 0...");System.out.println("y su estado es: "+sem.toString());System.out.println("Ahora intentamos adquirirlo...");sem.tryAcquire();System.out.println("sin bloqueo por no conseguirlo");System.out.println("Ahora intentamos adquirirlo...");sem.tryAcquire(3L, TimeUnit.SECONDS);System.out.println("tras esperar lo indicado sin consguirlo...");sem.acquire();System.out.println("Aquí no llegaremos nunca...");

}}

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 9: Diapositivas del Tema 6

9

Protocolo de Control de E.M. con Semáforos// Thread A public void run(){try {

s.acquire();} catch (InterruptedException ex) { }//Bloque de código a ejecutar en e.ms.release();

}

// Thread B public void run(){try {

s.acquire();} catch (InterruptedException ex) { }//Bloque de código a ejecutar en e.ms.release();

}

//En el programa principal, hacer siempre Semaphore s = new Semaphore (1);

Page 10: Diapositivas del Tema 6

10

import java.util.concurrent.*;

public class Tarea_concurrenteextends Thread

{Semaphore s; //referencia a un semaforo común a otros hilospublic Tarea_concurrente(Semaphore param)

{s = param;}

public void run (){

for(;;){try {s.acquire();} catch (InterruptedException e) {}System.out.println("Hilo "+this.getName()+" entrando a

seccion critica");s.release();System.out.println("Hilo "+this.getName()+" saliendo de

seccion critica");}

}}

Ejemplo de Control de E.M. con Semáforos

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 11: Diapositivas del Tema 6

11

Descargue la clase Tarea_Concurrente.java y compileDescargue la clase Protocolo_em_semaphore.java, compile y ejecute.Diseñe, utilizando semáforos, un código cuyos hilos se interbloqueen:deadlockSem.java

EJERCICIO

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 12: Diapositivas del Tema 6

12

// Thread A public void esperarSeñal(semaphore s) {try {

s.acquire();} catch (InterruptedException ex) { }

}

// Thread B public void enviarSeñal(Semaphore s) {

s.release(); }

//En el programa principal, hacer siempre Semaphore s = new Semaphore (0);

Protocolo de Sincronización Inter-Hilos con Semáforos

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 13: Diapositivas del Tema 6

13

import java.util.concurrent.*;class HiloReceptor extends Thread{

Semaphore sem;public HiloReceptor(Semaphore s){sem = s;}public void run(){System.out.println("Hilo Receptor esta esperando la senal");try{sem.acquire();} catch (InterruptedException e) {}System.out.println("Hilo Receptor ha recibido la senal");

}}

class HiloSenalador extends Thread{ Semaphore sem;

public HiloSenalador(Semaphore s){sem = s;}public void run(){sem.release();System.out.println("Hilo Senalador enviando senal...");

}}public class protocolo_sincronizacion_semaphore {

public static void main(String[] args){ int v_inic_sem = 0;Semaphore s = new Semaphore(v_inic_sem);new HiloReceptor(s).start();new HiloSenalador (s).start();

}} © Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 14: Diapositivas del Tema 6

14

Utilizando las semáforos que sean necesarios, provea la sincronización por turno cíclico de tres hilos diferentes. Nombre sus ficheros HA.java, HB.java,…Implante ahora una lector-escritor con semáforos. Nombre sus ficheros LE1.java, LE2.java,…

EJERCICIO

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 15: Diapositivas del Tema 6

15

Una barrera es un punto de espera a partir del cuál todos los hilos se sincronizanNingún hilo pasa la barrera hasta que todos los hilos esperados llegan a ellaUtilidad

Unificar resultados parcialesInicio siguiente fase ejecución simultánea

La clase java.util.concurrent.CyclicBarrier

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 16: Diapositivas del Tema 6

16

// Codigo de Threadpublic Hilo extends Thread {P ublic Hilo (CyclicBarrier bar){…}public void run() {try {int i = bar.await();}

catch (BrokenBarrierException e) {}catch (InterruptedException e) {}

//codigo a ejecutar cuando se abre barrera…}

}}

//En el programa principal, hacer siempre int numHilos = n; //numero de hilo que abren barreraCyclicBarrier Barrera = new CyclicBarrier (numHilos);new Hilo(Barrera).start();

Protocolo de Barrera

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 17: Diapositivas del Tema 6

17

import java.util.concurrent.*;

class Hilo extends Thread{CyclicBarrier barrera = null;

public Hilo (CyclicBarrier bar){barrera = bar;}

public void run(){try {int i = barrera.await();}

catch (BrokenBarrierException e) {}catch (InterruptedException e) {}

System.out.println("El hilo "+this.toString()+" paso la barrera...");

}}

public class UsaBarreras {public static void main(String[] args) {int numHilos = 3;

CyclicBarrier PasoANivel = new CyclicBarrier (numHilos);new Hilo(PasoANivel).start();

}}© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 18: Diapositivas del Tema 6

18

EJERCICIO

Un vector de 100 enteros es escalado mediante f(v[i])=v[i]2.

Posteriomente el vector se suma entero en un único número.Escriba un programa en java multihebrado (utilizando barreras) que realice la tarea: vectSum.java

Page 19: Diapositivas del Tema 6

19

Proporciona clases para establecer sincronización de hilos alternativas a los bloques de código sincronizado y a los monitoresClases e interfaces de interés:

ReentrantLock: proprociona cerrojos de e.m. de semántica equivalente a synchronized, pero con un manejo más sencillo.LockSupport: proporciona primitivas de bloqueo de hilos que permiten al programador diseñar sus clases de sincronización y cerrojos propiosCondition:es una interface, cuyas instancias se usan asociadas a locks. Implementan variables de condición y proporcionan una alternativa de sincronización a los métodos wait, notify y notifyAll de la clase Object.

El API java.util.concurrent.locks

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 20: Diapositivas del Tema 6

20

Proporciona cerrojos reentrantes de semántica equivalente a synchronized.Métodos lock()-unlock()Método isLocked()Método Condition newCondition() que retorna una variable de condición asociada al cerrojo

El API de la clase ReentrantLock

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 21: Diapositivas del Tema 6

21

Definir el recurso compartido donde sea necesarioDefinir un objeto c de clase ReentrantLock para control de la exclusión mutua.Acotar la sección crítica con el par c.lock() y c.unlock()

Protocolo de Control de E.M. con ReentrantLock

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 22: Diapositivas del Tema 6

22

class Usuario { private final ReentrantLock cerrojo = new ReentrantLock();

// ... public void metodo() { cerrojo.lock();try { // ... cuerpo del metodo en e.m. }

finally {cerrojo.unlock() } }

}

NOTA: Semántica equivalente a haber etiquetado el segmento de código crítico como synchronized. Útil para adaptar código concurrente antiguo a java 5.

Protocolo de Control de E.M. con ReentrantLock

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 23: Diapositivas del Tema 6

23

Escribir un protocolo de e.m. con cerrojos ReentrantLock y guardarlo en eMRL.java. Escribir una clase que lo use.Descargue otra vez nuestra vieja clase Cuenta_Banca.javaDecida que código debe ser sincronizado, y sincronícelo con cerrojos ReentrantLock. La nueva clase será Cuenta_Banca_RL.javaEscriba un programa multihebrado que use objetos de la clase anterior.LlámeloUsa_Cuenta_Banca_Sync.java

EJERCICIOS

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 24: Diapositivas del Tema 6

24

Proporciona variables de condiciónSe usa asociada a un cerrojo: siendo cerrojo una instancia de la clase ReentrantLock,cerrojo.newCondition() retorna la variable.Operaciones: await(), signal(), signalAll()

La Interfaz Condition

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 25: Diapositivas del Tema 6

25

import java.util.concurrent.locks.*;

class buffer_acotado {final Lock cerrojo = new ReentrantLock(); //declara y crea un cerrojofinal Condition noLlena = cerrojo.newCondition(); //obtiene variables de condicion asociadas a cerrojofinal Condition noVacia = cerrojo.newCondition(); //para control de buffer lleno y vacio

final Object[] items = new Object[100]; //array de objetosint putptr, takeptr, cont; //punteros de insercion y extracción

public void put(Object x) throws InterruptedException {cerrojo.lock();try {while (cont == items.length)noLlena.await(); //duerme a hilo productor si buffer lleno

items[putptr] = x;if (++putptr == items.length) putptr = 0;++cont;noVacia.signal(); //despierta a hilo consumidor esperando presencia de datos en buffer

} finally {cerrojo.unlock();}}

public Object take() throws InterruptedException {cerrojo.lock();try {while (cont == 0)noVacia.await(); //duerme a hilo consumidor si buffer vacio

Object x = items[takeptr];if (++takeptr == items.length) takeptr = 0;--cont;noLlena.signal(); //despierta a hilo productor esperando presencia de huecos en bufferreturn x;

} finally {cerrojo.unlock();}}

}

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 26: Diapositivas del Tema 6

26

Descargue y compile la clase buffer_acotado.java¿Qué diferencias tiene con la clase Buffer.java? (carpeta código Tema5)Implemente ahora hilos productores y consumidores que usen el buffer acotado y láncelos. Llame a su código prod_con_condition.java

EJERCICIOS

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 27: Diapositivas del Tema 6

27

A partir de Java 5 se incorporan versiones sincronizadas de las principales clases contenedorasDisponibles en java.util.concurrentClases: ConcurrentHashMap, ConcurrentSkipListMap, ConcurrentSkipListSet, CopyOnWriteArrayList, y CopyOnWriteArraySet

Clases Contenedoras Sincronizadas

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 28: Diapositivas del Tema 6

28

A partir de Java 5 se incorporan diferentes versiones de colas, todas ellas sincronizadasDisponibles en java.util.concurrentClases: LinkedBlockingQueue, ArrayBlockingQueue, SynchronousQueue, PriorityBlockingQueue,y DelayQueue

Colas Sincronizadas

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 29: Diapositivas del Tema 6

29

Son seguras frente a hilos concurrentesProporcionan notificación a hilos según cambia su contenido Son autosincronizadas. Pueden proveer sincronización (además de e.m.) por sí mismasFacilitan enormemente la programación de patrones de concurrencia como el P-S

Caracterísicas

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 30: Diapositivas del Tema 6

30

import java.util.concurrent.*;

public class Productorimplements Runnable

{

LinkedBlockingQueue<Integer> data;Thread hilo;

public Productor(LinkedBlockingQueue<Integer> l){

this.data = l;hilo = new Thread (this);hilo.start();

}

public void run(){try {for(int x=0;;x++){data.put(new Integer(x)); //bloqueo de hilo si no hay huecoSystem.out.println("Insertando "+x);

}}

catch(InterruptedException e){}}

} © Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 31: Diapositivas del Tema 6

31

import java.util.concurrent.*;

public class Consumidorimplements Runnable

{

LinkedBlockingQueue<Integer> data;Thread hilo;

public Consumidor(LinkedBlockingQueue<Integer> l){

this.data = l;hilo = new Thread (this);hilo.start();

}

public void run(){try {for(;;) //bloquea a hilo consumidor si no hay datos…

System.out.println("Extrayendo "+data.take().intValue());}

catch(InterruptedException e){}}

}

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 32: Diapositivas del Tema 6

32

Descargue (subcarpeta colecciones seguras) Productor.java, Consumidor.java y ProdConColaBloqueante.java

Ejecute. ¿Cómo explica el comportamiento observado?Modificaciones:

Aumente el número de ranuras de la colaActive varios productores y un consumidorActive un productor y varios consumidores

EJERCICIOS

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 33: Diapositivas del Tema 6

33

Usamos colecciones a través de interfaces (usabilidad del código)Usar colecciones no sincronizadas no mejora mucho el rendimientoProblemas con esquema tipo productor-consumidor, use colasMinimice la sincronización explícitaSi con una colección retarda sus algoritmos, distribuya los datos y use varias

USO CORRECTO DE COLECCIONES

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 34: Diapositivas del Tema 6

34

Hipótesis: Se desea implantar un servidor web.Enfoques posibles:

Implantación de hilo simpleImplantación multihebrada

POOL DE HILOS (Thread Pools)

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 35: Diapositivas del Tema 6

35

class ServidorWebHiloUnico {public static void main(String[] args) throwsIOException {

ServerSocket socket = new ServerSocket(80);//aquí servidor escuchando puerto 80

while (true) {Socket connection = socket.accept();procesarSolicitud(connection);

}}

}

PATRÓN DE SERVIDOR WEB DE HILO SIMPLE

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 36: Diapositivas del Tema 6

36

class ServidorWebMultiHebrado {public static void main(String[] args) throws IOException {ServerSocket socket = new ServerSocket(80);//aquí servidor a la escucha en puerto 80//un hilo por solicitud

while (true) {final Socket connection = socket.accept();Runnable task = new Runnable() {public void run() {procesarSolicitud(connection);

}};new Thread(task).start();}//while

}}

PATRÓN DE SERVIDOR WEB MULTIHEBRADO

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 37: Diapositivas del Tema 6

37

Servidor de hilo simple es ineficiente (hay mucha latencia)Servidor multihebrado mejora la situación

Procesa múltiples solicitudes concurrentementeMejora el rendimiento general

Pero no está exento de problemas:Consumo de recursos (al crear los hilos)Estabilidad (número de peticiones elevado)

Alternativa: Utilizar un pool de hilos y un ejecutor.

COMPARATIVA

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 38: Diapositivas del Tema 6

38

Un pool de hilos es un conjunto de hilos inactivos a la espera de trabajoSi el programa tienen una tarea que ejecutar, la pasa al pool, que asigna un hilo para ejecutarlaUna vez acabada, el hilo vuelve a quedar a la espera de trabajo

CONCEPTO DE THREAD POOL

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 39: Diapositivas del Tema 6

39

EL PATRÓN DE THREAD POOL

© Antonio Tomeu El Lenguaje Java y la Programación Concurrente© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 40: Diapositivas del Tema 6

40

Crear un hilo es costoso (latencias). Creando un pool, creamos los hilos una vez y los reutilizamos varias.Permite un mejor diseño de programas, delegando la gestión del ciclo de vida de los hilos al poolPermite paralelizar las aplicaciones si se dispone de varios procesadores

¿Por qué usar un THREAD POOL?

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 41: Diapositivas del Tema 6

41

Un ejecutor es un concepto genérico, modelado por esta interfazProporcionan un patrón de diseño para programas multihebrados, modelándolos como una serie de tareas.Abstracción de los hilos; se crea una tarea, y se pasa al ejecutorJava 5 proporciona dos clases de ejecutores (implementan la interfaz):

Ejecutor de un Thread PoolEjecutor de tareas programadas

La interfaz java.util.concurrent.Executor

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 42: Diapositivas del Tema 6

42

package java.util.concurrent;

public interface Executor{

public void execute (Runnabletarea)

La interfaz java.util.concurrent.Executor

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 43: Diapositivas del Tema 6

43

La Clase ThreadPoolExecutor

Sirve para crear un pool de hilosImplementa a ExecutorServiceEl constructor:

public ThreadPoolExecutor(int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue<Runnable> workQueue); © Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 44: Diapositivas del Tema 6

44

public class Tarea implements Runnable {

int numTarea;

public Tarea(int n) {numTarea = n;}

public void run()

{for (int i=1; i<100; i++){ System.out.println("Esta es la tarea numero: "+numTarea+ "

imprimiendo "+i);}

}

}

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 45: Diapositivas del Tema 6

45

import java.util.concurrent.*;

public class pruebaThreadPool {public static void main(String[] args) {

int nTareas = Integer.parseInt(args[0]);int tamPool = Integer.parseInt(args[1]);

ThreadPoolExecutor miPool = new ThreadPoolExecutor(tamPool, tamPool, 60000L,TimeUnit.MILLISECONDS,

new LinkedBlockingQueue<Runnable>());

Tarea[] tareas = new Tarea [nTareas];for (int i=0; i<nTareas; i++){

tareas[i] = new Tarea(i);miPool.execute(tareas[i]);

}miPool.shutdown();

}}

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 46: Diapositivas del Tema 6

46

import java.net.*;import java.io.*;import java.util.concurrent.*;

public class SocketWebServerThreadPool implements Runnable {Socket enchufe;

public SocketWebServerThreadPool(Socket s){enchufe = s;}

public void run() {try{ BufferedReader entrada = new BufferedReader( newInputStreamReader(enchufe.getInputStream()));

String datos = entrada.readLine();int j; int i = Integer.valueOf(datos).intValue();for(j=1; j<=20; j++) System.out.println("Una tarea de servicio

escribiendo el dato "+i);enchufe.close();System.out.println("La tarea de servicio cierra su conexion...");} catch(Exception e) {System.out.println("Error...");}

}//run

UN SERVIDOR DE SOCKETS CON POOL DE THREADS

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 47: Diapositivas del Tema 6

47

public static void main (String[] args) {int i; int puerto = 2001;int nTareas = Integer.parseInt(args[0]);int tamPool = Integer.parseInt(args[1]);

ThreadPoolExecutor miPool = new ThreadPoolExecutor(tamPool, tamPool, 60000L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());

try{ ServerSocket chuff = new ServerSocket(puerto, 3000);while (true){

System.out.println("Esperando solicitud de conexion...");Socket cable = chuff.accept();System.out.println("Recibida solicitud de conexion...");

miPool.execute(new SocketWebServerThreadPool(cable));}//while

} catch (Exception e) {System.out.println("Error en sockets...");}}//main

}

© Antonio Tomeu API Java para Concurrencia de Alto Nivel

Page 48: Diapositivas del Tema 6

48

Descargar y compilar Tarea.java y pruebaThreadPool.javaAbrir el administrador de tareasEfectuar las siguientes pruebas:java pruebaThreadPool n mPara n=200 y m creciente

Implante ahora un protocolo productor-consumidor con un único buffer, y un pool de 8 tareas productoras y 6 consumidoras

EJERCICIOS

© Antonio Tomeu API Java para Concurrencia de Alto Nivel