Buscar
Social
Ofertas laborales ES
« Kendo for Java | Main | ¿JAVA EE 7 llega en primavera? »
lunes
mar252013

Introducción a JSR 236 (concurrencia en Java EE 7)

NOTA: Artículo escrito por Arun Gupta el 5 de Diciembre de 2012, traducido y adaptado al español por Jaime Carmona Loeches, miembro de la comunidad JavaHispano, el 25 de Marzo de 2013.

 

Utilidades de concurrencia para Java EE: borrador preliminar (JSR 236).

 

INTRODUCCIÓN

Las utilidades de concurrencia para Java EE se están desarrollando bajo la JSR 236, y han publicado un borrador preliminar.

Su objetivo es proporcionar capacidad de concurrencia a los componentes de la aplicación Java EE, sin compromenter la integridad del contenedor.

Para ello, se utilizarán patrones simples que serán integrados fácilmente en el servidor de aplicaciones, haciendo fácil su uso y favoreciendo la integración.

Como muchos sabemos, hace tiempo que existen las utilidades de concurrencia de Java Se 6 (interfaces java.util.concurrent, java.lang.Thread y java.util.Timer). Estas utilidades se podían utilizar de manera correcta en aplicaciones Java standalone (que corrían directamente en la máquina virtual).

Sin embargo, se producían problemas de sincronización al integrarlas en componentes que dependendían de un servidor de aplicaciones, como un Servlet o un EJB.

La especificación JSR 236 nace con la idea de integrar la concurrencia desarrollada previamente en la JSR 166 en los servidores de aplicación de Java EE. Los hilos pasan a ser manejados y proporcionados por el propio contenedor.

 

NO ME CUENTES ROLLOS, Y ENSEÑAME LÍNEAS DE CÓDIGO, CHAVAL

De acuerdo, pasemos de la teoría a la acción. Existen cuatro interfaces de programación principales:

  • ManagedExecutorService
  • ManagedScheduledExecutorService
  • ContextService
  • ManagedThreadFactory

Empezamos por la primera: ManagedExecutorService

Es una versión manejada de  java.util.concurrent.ExecutorService.

Es el contenedor quien proporciona la implementación....

<resource-env-ref>
  <resource-env-ref-name>
    concurrent/BatchExecutor
  </resource-env-ref-name>
  <resource-env-ref-type>
    javax.enterprise.concurrent.ManagedExecutorService
  </resource-env-ref-type>
<resource-env-ref>

y quien la ofrece vía JNDI...

Desde código, podemos acceder de la siguiente manera:

@Resource(name="concurrent/BatchExecutor")
ManagedExecutorService executor;

(NOTA: es recomendable enlazar las referencias de JNDI en el subcontextojava:comp/env/concurrent)

Las tareas asíncronas que necesitan ser ejecutadas necesitan implementar una de las siguientes interfaces:

o bien java.lang.Runnable 

public class MyTask implements Runnable {
 public void run() {
 // business logic goes here
 }
}

o bien java.util.concurrent.Callable

public class MyTask2 implements Callable {
  public Date call() {
 // business logic goes here 
  }
}

La tarea es entonces enviada al ejecutor, usando el método submit, que retorna una instancia Future.

Future permite conocer el resultado de una tarea, y nos permite conocer si la tarea se ha completado o está pendiente de hacerlo. Veamos un ejemplo:

Future future = executor.submit(new MyTask(), String.class); .......

String result = future.get();

La tarea correrá en un thread separado proporcionado y administrado por el contenedor.

Otro ejemplo podría ser el siguiente:

class MyTask implements Callable { . . . }

class MyTask2 implements Callable { . . . }

ArrayList tasks = new ArrayList<();

tasks.add(new MyTask());

tasks.add(new MyTask2());

List> result = executor.invokeAll(tasks);

En este ejemplo, podríamos enviar al servidor la ejecución de varias tareas, no de una sólo....

 

Siguiente intefaz: ManagedExecutorService.

Dicha interfaz puede ser configurada para definir una gran variedad de propiedades como: 

  • Umbral de colgado de tarea (Hung Task Threshold): tiempo en milisegundos desde que una tarea se ejecutada hasta que se considera que se ha quedado "colgada".
  • Información del pool 
    • Tamaño de hilos vivos: número de hilos que se mantienen vivos.
    • Tamaño máximo total: máximo número de hilos permitidos en el pool.
    • Tiempo de inactividad: tiempo asignado a los hilos para permanencer inactivos cuando el número de hilos supera el tamaño máximo del core.
    • Capacidad de trabajo de la cola: número de tareas que pueden ser almacenadas en el  buffer entrante.
  • Uso de hilos: la aplicación  intenta ejecutar tareas cortas contra tareas largas, teniendo en cuenta los hilos que están en el pool,  o los que están en el demonio, y cuáles son escogidos.

(NOTA: La especificación no obliga a definir ningún atributo de configuración. Los ejemplos mencionados anteriormente son sólo ejemplos y pueden no ser soportados por todos los servidores de aplicación)

Pasamos a la interfaz ManagedScheduledExecutorService.

Esta interfaz añade retrasos y táreas períodicas de capacidad a la interfaz ManagedExecutorService.

Las implementaciones de esta interfaz son proporcionadas por el contenedor y accesible usando la referencia JNDI... (como vimos en la primera interfaz, llamada ManagedExecutorService).

Veamos un ejemplo:

<resource-env-ref>
  <resource-env-ref-name>
    concurrent/BatchExecutor
  </resource-env-ref-name>
  <resource-env-ref-type>
    javax.enterprise.concurrent.ManagedExecutorService
  </resource-env-ref-type>
<resource-env-ref>

y disponible de la siguiente manera:

@Resource(name="concurrent/timedExecutor")
ManagedExecutorService executor;

Las táreas son enviadas entonces utilizando los métodos submit, invokeXXX o scheduleXXX.

ScheduledFuture<?> future = executor.schedule(new MyTask(), 5, TimeUnit.SECONDS);

Esta línea creará y ejecutará una acción que se habilitará con 5 segundos de retraso.

Más control es posible utilizando uno de los nuevos métodos añadidos:

MyTaskListener implements ManagedTaskListener {
  public void taskStarting(...) { . . . }
  public void taskSubmitted(...) { . . . }
  public void taskDone(...) { . . . }
  public void taskAborted(...) { . . . } }
ScheduledFuture<?> future = executor.schedule(new MyTask(), 5, TimeUnit.SECONDS, new MyTaskListener());

Aquí, ManagedTaskListener se utiliza para monitorear el estado de una tarea de futuro.

Veamos la siguiente interfaz, ManagedThreadFactory.

 Dicha interfaz proporciona un método para crear threads que permiten la ejecución en un entorno  gestionado.

Un ejemplo simple sería el siguiente:

@Resource(name="concurrent/myThreadFactory")
ManagedThreadFactory factory;
. . .
Thread thread = factory.newThread(new Runnable() { . . . });

siendo concurrent/myThreadFactory un recurso JNDI.

Hay mucho contenido interesante en el Early Draft, puedes descargarlo y leerlo.

La implementación llegará un poco más adelante y será integrada en el servidor de aplicaciones GlassFish4.

 

Más información sobre la materia en:

  • http://gee.cs.oswego.edu/dl/concurrencyee-interest/JavaOne-EEConcurrency.pdf
  • http://jcp.org/en/jsr/detail?id=236

 

PrintView Printer Friendly Version

EmailEmail Article to Friend

Reader Comments (2)

Soy yo o es que esta nueva especificación es muy pero que muy parecida a lo existente actualmente. O sea, hay algo nuevo que antes no se pudiera hacer? Lo pregunto desde el desconocimiento, sin ganas de trollear.

marzo 26, 2013 | Unregistered CommenterAlonso

Hola Alonso,
El objetivo de esta especificación es partir de algo existente (que funcionaba a la perfección en aplicaciones Java que corrían contra la JVM), para integrarlo en servidores J2ee.
Se parte de lo ya existente (que es lo que tu comentas), pero ahora los hilos son ofrecidos y gestionados directamente por el contenedor J2ee, lo que entiendo que permite sincronizar mejor dichos hilos con otros ya existentes sin provocar problemas...

No sé si te habrás encontrado con un IllegalStateException infinito en Tomcat (si tienes un hilo en ejecución y paras la el servidor web.... dicho hilo nunca muere, salvo matada de proceso).

http://www.javahispano.org/certificacion/2013/1/18/gestion-de-hilos-dentro-de-una-aplicacion-web-de-tomcat.html

marzo 26, 2013 | Registered Commenterjcarmonaloeches

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>