PDF de programación - Tema 6 - Tareas y patrones de diseño para concurrencia - Programación Avanzada

Imágen de pdf Tema 6 - Tareas y patrones de diseño para concurrencia - Programación Avanzada

Tema 6 - Tareas y patrones de diseño para concurrencia - Programación Avanzadagráfica de visualizaciones

Publicado el 18 de Diciembre del 2018
1.244 visualizaciones desde el 18 de Diciembre del 2018
767,0 KB
48 paginas
Creado hace 11a (11/03/2013)
Asignatura 780014

Programación Avanzada

Tema 6 – Tareas y patrones de diseño para concurrencia

© [email protected]

Tareas y Threads

Por ahora:

– Programa concurrente = preparación + actividades concurrentes

– Actividad concurrente = Thread nuevo


Nueva posibilidad:

– Una actividad concurrente es una tarea independiente de las otras

• Definida como una unidad de trabajo abstracta y discreta


Concepto útil en C/S:

– Cada cliente y respuesta del servidor es una tarea

– Incrementa la capacidad de prestar servicios (throughput)

– Mejora tiempos de respuesta (responsiveness) con carga normal

– Mejora el ritmo de degradación de prestaciones con carga se elevada

Estrategias de ejecución

Estrategias para ejecutar tareas:

– Secuencial

• Bajo “throughput”, tiempo de respuesta malo


– Un Thread por tarea

• Mejor uso de recursos
• Para tareas breves, la creación/destrucción de Thread es sobrecarga
• Con carga baja buena respuesta, con carga alta peligro de agotamiento


– Un grupo de Thread a reutilizar (pool)

• Se elimina sobrecarga por creación/destrucción
• Se limitan los recursos reservados
• Se alcanza estabilidad en carga alta

Las tres estrategias en esquema visual

Estrategias erróneas

Ejemplo:

– Web server que acepta conexiones por sockets en el puerto 80

– Para cada petición crea un thread nuevo

Pocos clientes



class UnreliableWebServer
{
public static void main(String[] args)
{
ServerSocket socket = new ServerSocket(80);
while (true)

{
final Socket connection = socket.accept();
Runnable r = new Runnable() { public void run() { handleRequest(connection); } };
}
//¡No hacer esto!
new Thread(r).start();
}
}



Muchos clientes

– Sólo será capaz de atender a un número reducido de clientes

Estrategia eficaz, pool de hilos

• Estructura superior al hilo que agrupa y gestiona varios hilos

– Ejecuta tareas organizadas en una cola

• Habrá más tareas que Thread

– Cada Thread puede ejecutar una tarea cada vez
– El número de Thread puede variar según necesidades
– Se pueden repartir los pools por granjas de servidores

Algoritmo de comportamiento

de cada Thread

while (true)
{
if (no tasks) wait for a task;
execute the task;
}

Pool de hilos en java

Implementado mediante el Framework Executor:

– Conjunto de interfaces

– Ejecución concurrente y asíncrona de tareas


La base del framework es la interfaz Executor

– Describe un objeto para ejecutar Runnables
public interface Executor

{

void execute(Runnable command);

}


Flexibiliza el mantenimiento

– Permite cambios de las políticas de ejecución sin cambiar el código

Políticas de ejecución en Java

En el framework Executor podemos aplicar políticas de ejecución

– Una política de ejecución incluye:

• Definir en que Thread se ejecutan las tareas

• Definir el orden en el que se ejecutan las tareas

• El número de tareas que se permiten ejecutar concurrentemente

• El número de tareas que pueden encolarse en espera de ejecución

• Selección de la tarea que debe ser rechazada si hay sobrecarga

• Definir acciones a ejecutar antes y después de una tarea



– Una política es una herramienta de gestión de recursos.

• La óptima depende de:

– Los recursos disponibles

– La calidad de servicio (throughput) que se requiere

Ciclo de vida de los Executors

Usando la interfaz ExecutorService

– Se maneja el ciclo de vida de un servicio executor:

public interface ExecutorService extends Executor
{
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit);

// Otros métodos convenientes para iniciar tareas

}

Interfaz ExecutorService

ExecutorService ofrece

– Servicios para controlar ciclo de vida de los Thread pool

– Un thread pool sigue un ciclo de vida con tres estados:


• Running: Cuando se crea y en régimen normal de funcionamiento.

– Admite tareas y cuando tiene threads disponibles los ejecuta.


• Shutting down: Terminando gradualmente.

– No acepta nuevas tareas, pero las que están en colase ejecutan

(aunque no hayan iniciado su ejecución)



• Terminated: Finalización abrupta.

– Trata de finalizar las tareas en ejecución, y ni admite nuevas

tareas, ni comienza la ejecución de tareas en cola.

La clase ThreadPoolExecutor

class ThreadPoolExecutor implements ExecutorService

– Tiene 4 constructores
– Los cuatro tienen en común:



int corePoolSize, // Número inicial de Thread que se crean

int maximumPoolSize, // Número máximo de threads que se pueden crear

long keepAliveTime, TimeUnit unit, // Tiempo para destruir Thread que sobran hasta corePoolSize

BlockingQueue<Runnable> workQueue, //Tipo de cola de tareas


– Además podemos tener: ningún parámetro más, uno de los dos siguientes o los dos:



ThreadFactory threadFactory, // Política con las que se crean los thread dinámicamente



// (Prioridad, Grupo, naturaleza)

RejectedExecutionHandler handler) // Define la política con la que se descartan las tareas

// tareas cuya ejecución es rechazada, bien por shutdown

// o por cola de tareas limitada

Tipos de pool de hilos

Crear pools con ThreadPoolExecutor es complejo:

– Es recomendable usar los métodos de factoría:

• Executors.newCachedThreadPool()

• Executors.newFixedThreadPool(int n)

• Executors.newSingleThreadExecutor()

• Executors.newScheduledThreadPool(int n)



– Estos métodos devuelven un ExecutorService

Executors.newCachedThreadPool()

Pool de threads no está limitado
en tamaño

– Puede reutilizar threads creados

previamente cuando se quedan
libres

– Si no hay ningún thread

disponible para una tarea nueva,
se crea uno

– Los threads que no han sido

utilizados durante un minuto, se
destruyen.

Qué pasaría si…:

1.Sistema inactivo
2.Llegan 10 tareas simultáneamente
3.Pasan 10 segundos
4.Llegan 5 tareas simultáneamente
5.Pasan 5 minutos
6.Llegan 20 tareas simultáneamente.


Tareas de entre 5 y 15
segundos para procesarse.

Executors.newFixedThreadPool(int n)

Pool que reutiliza un conjunto
fijo de threads

– Con una cola compartida

de tareas

– Si termina algún thread

debido a un fallo durante la
ejecución (antes del
shutdown), se vuelve a
crear uno nuevo para
sustituirlo.

Qué pasaría si…:

1.Sistema inactivo
2.Llegan 10 tareas simultáneamente
3.Pasan 10 segundos
4.Llegan 5 tareas simultáneamente
5.Pasan 5 minutos
6.Llegan 20 tareas simultáneamente.

Tareas de entre 5 y 15
segundos para procesarse.

Executors.newSingleThreadExecutor()

Crea un pool con un único thread

– Operando sobre una cola de

tareas

– Es el modelo seguido por el Swing

event thread

– Garantiza que las tareas se
ejecutan secuencialmente

– Garantiza que solamente hay una

activa en cualquier momento
dado

Qué pasaría si…:

1.Sistema inactivo
2.Llegan 10 tareas simultáneamente
3.Pasan 10 segundos
4.Llegan 5 tareas simultáneamente
5.Pasan 5 minutos
6.Llegan 20 tareas simultáneamente.

Tareas de entre 5 y 15
segundos para procesarse.

Executors.newScheduledThreadPool(int n)

Crea crea un pool que va a ir
ejecutando tareas programadas
cada cierto tiempo

– Puede ser en un instante dado

o de manera repetitiva

– Es parecido a un timer

• Con la diferencia de que

puede tener varios threads
para poder realizar varias
tareas programadas
simultaneamente

Qué pasaría si…:

1.Sistema inactivo
2.Llegan 10 tareas simultáneamente
3.Pasan 10 segundos
4.Llegan 5 tareas simultáneamente
5.Pasan 5 minutos
6.Llegan 20 tareas simultáneamente.

Tareas de entre 5 y 15
segundos para procesarse.

Gestión de tareas correcta

Ejemplo de un web server

– Acepta conexiones por sockets en el puerto 80

– Dispone de un pool de 7 threads para atender clientes



class ReliableWebServer
{
Executor pool = Executors.newFixedThreadPool(7);
public static void main(String[] args)
{
ServerSocket socket = new ServerSocket(80);
while (true)
{
final Socket connection = socket.accept();
Runnable r = new Runnable() { public void run() {handleRequest(connection);} };
pool.execute(r);
}
}
}

Ejemplo de finalización de las tareas del pool

Suponiendo que tuviéramos un botón en la interfaz gráfica que controla el Web Server:
private void jButtonApagar (ActionEvent evt)
{
pool.shutdown(); // No deja entrar nuevas tareas
try { // Espera durante 1 min. para ver si han terminado ya
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
{
pool.shutdownNow(); // Fuerza la terminación de las tareas
//Espera otro minuto para ver si el pool ya ha terminado
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("El pool no terminó");
}
} catch (InterruptedException ie) { // (Re-)Cancela el pool
pool.shutdownNow();
Thread.currentThread().interrupt(); //Preserva el interrupt
}
}

Tareas con resultados demorados

En el Framework Executor,

– Las tareas son objetos que implementan la interfaz Runnable,

– Su ejecución en el método public void run(){…}

– Con algunas limitaciones:
  • Links de descarga
http://lwp-l.com/pdf14577

Comentarios de: Tema 6 - Tareas y patrones de diseño para concurrencia - Programación Avanzada (0)


No hay comentarios
 

Comentar...

Nombre
Correo (no se visualiza en la web)
Valoración
Comentarios...
CerrarCerrar
CerrarCerrar
Cerrar

Tienes que ser un usuario registrado para poder insertar imágenes, archivos y/o videos.

Puedes registrarte o validarte desde aquí.

Codigo
Negrita
Subrayado
Tachado
Cursiva
Insertar enlace
Imagen externa
Emoticon
Tabular
Centrar
Titulo
Linea
Disminuir
Aumentar
Vista preliminar
sonreir
dientes
lengua
guiño
enfadado
confundido
llorar
avergonzado
sorprendido
triste
sol
estrella
jarra
camara
taza de cafe
email
beso
bombilla
amor
mal
bien
Es necesario revisar y aceptar las políticas de privacidad