Tareas de API de ejemplo que implementan Concurrency Utilities for Java EE
Puede migrar aplicaciones que utilizan beans asíncronos y CommonJ Timer y las API del gestor de trabajos para utilizar Concurrency Utilities for Java™ EE.
Concurrency Utilities for Java EE proporciona un enfoque estandarizado para realizar operaciones simultáneas en un servidor de aplicaciones. Sustituye los modelos de programación para beans asíncronos y CommonJ Timer y el gestor de trabajos.
- Recursos utilizados en los ejemplos de código
- Implementación de tarea básica
- Envío de una tarea
- Espera de la finalización de un grupo de tareas
- Espera de la finalización de una sola tarea dentro de un grupo
- Obtener la excepción de causa cuando falla una tarea
- Planificación de una tarea única para ejecutarse después de un intervalo
- Planificación de una tarea periódica a un ritmo fijo y consulta del intervalo hasta la siguiente ejecución
- Planificación de una tarea periódica para ejecutarse a distintos intervalos
- Suspensión y reanudación de la ejecución de tareas
- Detener ejecución adicional tareas
- Construcción de proxies contextuales
- Construcción de proxies contextuales para varias instancias que se ejecutan en la transacción de la hebra de ejecución
- Creación de tareas contextuales para la ejecución diferida en la hebra de invocación
- Más opciones para tareas contextuales para la ejecución diferida
- Supervisión de subsistema
- Manejo de sucesos
- Manejo de sucesos para una anomalía que se produce durante la invocación de un proxy contextual
Recursos utilizados en los ejemplos de código
Los ejemplos de código de esta página dan por supuesto que la aplicación ha inyectado o buscado los recursos siguientes:
@Resource(lookup = "wm/default")
private com.ibm.websphere.asynchbeans.WorkManager abWorkManager;
@Resource(lookup = "wm/default")
private commonj.work.WorkManager cjWorkManager;
@Resource
private ContextService contextService;
@Resource(name = "java:app/env/jdbc/dsRef")
private DataSource dataSource;
@Resource
private ManagedScheduledExecutorService executor;
@Resource
private ManagedThreadFactory threadFactory;
@Resource(name = "java:comp/env/tm/default", lookup = "tm/default", shareable = false)
private TimerManager timerManager;
@Resource
private UserTransaction tran;
Implementación de tarea básica
Esta sección proporciona algunos ejemplos de implementaciones de tarea sencillas que utilizan otros ejemplos en el resto de este documento. Los beans asíncronos requieren una interfaz independiente, AlarmListener, para las tareas que se han planificado para ejecutarse en el futuro. CommonJ requiere una interfaz independiente, TimerListener, para las tareas que se han planificado para ejecutarse en el futuro. Las tareas de Concurrency Utilities for Java EE pueden ser Runnable (ejecutables) o Callable (invocables), y permite que se utiliza cualquier interfaz, independientemente de si una tarea se ha enviado para ejecutarse de inmediato, o si se ha planificado para ejecutarse en el futuro. En algunos casos, es posible enviar beans asíncronos o trabajo de CommonJ como Runnable a un ejecutor gestionado sin ningún cambio. El método de trabajo release se sustituye por la capacidad de los ejecutores gestionado para cancelar e interrumpir las hebras en ejecución. El método de trabajo isDaemon se sustituye por la propiedad de ejecución LONGRUNNING_HINT.
Tarea Work de ejemplo para beans asíncronos y, también, CommonJ que busca el siguiente número primo:
public class PrimeFinderWork implements
com.ibm.websphere.asynchbeans.Work, commonj.work.Work {
private long num;
private volatile boolean released;
private long result;
public PrimeFinderWork(long startingValue) {
num = startingValue;
}
public boolean isDaemon() {
return false;
}
public void release() {
released = true;
}
public void run() {
while (!isPrime(num))
if (released || Thread.currentThread().isInterrupted())
throw new RuntimeException(new InterruptedException());
else
num++;
result = num++;
}
public long getPrimeNumber() {
if (result > 0)
return result;
else
throw new IllegalStateException();
}
}
Tarea AlarmListener de ejemplo para beans asíncronos que busca el siguiente número primo:
public class PrimeFinderAlarmListener implements AlarmListener {
private volatile boolean aborted;
private int count;
private long num;
private long result;
public PrimeFinderAlarmListener(long startingValue) {
num = startingValue;
}
public void abort() {
aborted = true;
}
public void fired(Alarm alarm) {
while (!isPrime(num))
if (aborted || Thread.currentThread().isInterrupted())
throw new RuntimeException(new
InterruptedException());
else
num++;
result = num++;
// optionally reschedule:
Object delays = alarm.getContext();
if (delays instanceof Integer)
alarm.reset((Integer) delays);
else if (delays instanceof int[] && count < ((int[]) delays).length)
alarm.reset(((int[]) delays)[count++]);
}
public long getPrimeNumber() {
if (result > 0)
return result;
else
throw new IllegalStateException();
}
Tarea TimerListener de ejemplo para beans asíncronos que busca el siguiente número primo:
public class PrimeFinderTimerListener implements
CancelTimerListener, TimerListener {
private volatile boolean aborted;
private int count;
private final long[] delays;
private long num;
private long result;
public PrimeFinderTimerListener(long startingValue, long... delays) {
num = startingValue;
this.delays = delays;
}
public void timerCancel(Timer timer) {
aborted = true;
}
public void timerExpired(Timer timer) {
while (!isPrime(num))
if (aborted || Thread.currentThread().isInterrupted())
throw new RuntimeException(new
InterruptedException());
else
num++;
result = num++;
// optionally reschedule:
if (count < delays.length)
try {
TimerManager timerManager = (TimerManager) new InitialContext().lookup(
"java:comp/env/tm/default");
timerManager.schedule(this, delays[count++]);
} catch (NamingException x) {
throw new RuntimeException(x);
}
}
public long getPrimeNumber() {
if (result > 0)
return result;
else
throw new IllegalStateException();
}
}
Ejemplo de una tarea Runnable para Concurrency Utilities for Java EE que busca el siguiente número primo:
public class PrimeFinderRunnable implements Runnable {
private long num;
private long result;
public PrimeFinderRunnable(long startingValue) {
num = startingValue;
}
public void run() {
while (!isPrime(num))
if (Thread.currentThread().isInterrupted())
throw new RuntimeException(new
InterruptedException());
else
num++;
result = num++;
}
public long getPrimeNumber() {
if (result > 0)
return result;
else
throw new IllegalStateException();
}
}
Ejemplo de una tarea Callable para Concurrency Utilities for Java EE que busca el siguiente número primo:
public class PrimeFinderTask implements Callable<Long> {
private long num;
public PrimeFinderTask(long startingValue) {
num = startingValue;
}
public Long call() throws InterruptedException {
while (!isPrime(num))
if (Thread.currentThread().isInterrupted())
throw new InterruptedException();
else
num++;
return num++;
}
}
Tarea Work de ejemplo para beans asíncronos que realiza una inserción de base de datos básica:
public class DBInsertWorkAB implements Work, Serializable {
private static final long serialVersionUID = 2606824039439594442L;
private transient Thread executionThread;
private final String code;
private final String name;
private boolean released;
private volatile int result = -1;
public DBInsertWorkAB(String code, String name) {
this.code = code;
this.name = name;
}
public int getResult() {
return result;
}
public synchronized void release() {
released = true;
if (executionThread != null)
executionThread.interrupt();
}
public void run() {
synchronized (this) {
if (released)
throw new RuntimeException("Work was canceled");
executionThread = Thread.currentThread();
}
try {
DataSource ds = (DataSource) new InitialContext().lookup(
"java:app/env/jdbc/dsRef");
Connection con = ds.getConnection();
try {
PreparedStatement stmt = con.prepareStatement(
"INSERT INTO AIRPORTS VALUES(?,?)");
stmt.setString(1, code);
stmt.setString(2, name);
result = stmt.executeUpdate();
} finally {
con.close();
}
} catch (NamingException x) {
throw new RuntimeException(x);
} catch (SQLException x) {
throw new RuntimeException(x);
} finally {
synchronized (this) {
executionThread = null;
}
}
}
}
Tarea AlarmListener de ejemplo para beans asíncronos que realiza una inserción de base de datos básica:
public class DBInsertAlarmListener implements AlarmListener {
private volatile int result = -1;
public int getResult() {
return result;
}
public void fired(Alarm alarm) {
String[] alarmContext = (String[]) alarm.getContext();
try {
DataSource ds = (DataSource) new InitialContext().lookup(
"java:app/env/jdbc/dsRef");
Connection con = ds.getConnection();
try {
PreparedStatement stmt = con.prepareStatement(
"INSERT INTO AIRPORTS VALUES(?,?)");
stmt.setString(1, alarmContext[0]);
stmt.setString(2, alarmContext[1]);
result = stmt.executeUpdate();
} finally {
con.close();
}
} catch (NamingException x) {
throw new RuntimeException(x);
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
}
Tarea Work de ejemplo para CommonJ que realiza una inserción de base de datos básica:
public class DBInsertWorkCJ implements Work, Serializable {
private static final long serialVersionUID = -8801347489043041978L;
private transient Thread executionThread;
private final String code;
private final String name;
private boolean isDaemon;
private boolean released;
private volatile int result = -1;
public DBInsertWorkCJ(String code, String name) {
this.code = code;
this.name = name;
}
public int getResult() {
return result;
}
public boolean isDaemon() {
return isDaemon;
}
public synchronized void release() {
released = true;
if (executionThread != null)
executionThread.interrupt();
}
public void run() {
synchronized (this) {
if (released)
throw new RuntimeException("Work was canceled");
executionThread = Thread.currentThread();
}
try {
DataSource ds = (DataSource) new InitialContext().lookup(
"java:app/env/jdbc/dsRef");
Connection con = ds.getConnection();
try {
PreparedStatement stmt = con.prepareStatement(
"INSERT INTO AIRPORTS VALUES(?,?)");
stmt.setString(1, code);
stmt.setString(2, name);
result = stmt.executeUpdate();
} finally {
con.close();
}
} catch (NamingException x) {
throw new RuntimeException(x);
} catch (SQLException x) {
throw new RuntimeException(x);
} finally {
synchronized (this) {
executionThread = null;
}
}
}
Tarea TimerListener de ejemplo para CommonJ qie realiza una inserción de base de datos básica:
public class DBInsertTimerListener implements
TimerListener {
private volatile int result = -1;
private final String code;
private final String name;
public DBInsertTimerListener(String code, String name) {
this.code = code;
this.name = name;
}
public int getResult() {
return result;
}
public void timerExpired(Timer timer) {
try {
DataSource ds = (DataSource) new InitialContext().lookup(
"java:app/env/jdbc/dsRef");
Connection con = ds.getConnection();
try {
PreparedStatement stmt = con.prepareStatement(
"INSERT INTO AIRPORTS VALUES(?,?)");
stmt.setString(1, code);
stmt.setString(2, name);
result = stmt.executeUpdate();
} finally {
con.close();
}
} catch (NamingException x) {
throw new RuntimeException(x);
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
}
Tarea Callable de ejemplo para Concurrency Utilities for Java EE que realiza una inserción de base de datos básica:
public class DBInsertTask implements
Callable<Integer>, Serializable {
private static final long serialVersionUID = 5556464104788801400L;
private final String code;
private final String name;
public DBInsertTask(String code, String name) {
this.code = code;
this.name = name;
}
public Integer call() throws NamingException, SQLException {
DataSource ds = (DataSource) new InitialContext().lookup(
"java:app/env/jdbc/dsRef");
Connection con = ds.getConnection();
try {
PreparedStatement stmt = con.prepareStatement(
"INSERT INTO AIRPORTS VALUES(?,?)");
stmt.setString(1, code);
stmt.setString(2, name);
return stmt.executeUpdate();
} finally {
con.close();
}
}
}
Envío de una tarea
Los tres modelos de programación proporcionan una forma de enviar una tarea básica para ejecutarse en una hebra agrupada y obtener el resultado.
Ejemplo de beans asíncronos
WorkItem workItem = abWorkManager.startWork(
new DBInsertWorkAB("DLH", "Duluth International Airport"));
ArrayList<WorkItem> items = new
ArrayList<WorkItem>(1);
items.add(workItem);
if (abWorkManager.join(items, WorkManager.JOIN_AND, TIMEOUT_MS)) {
DBInsertWorkAB work = (DBInsertWorkAB) workItem.getResult();
int numUpdates = work.getResult();
}
Ejemplo de CommonJ:
WorkItem workItem = cjWorkManager.schedule(
new DBInsertWorkCJ("HIB", "Chisholm-Hibbing Airport"));
if (cjWorkManager.waitForAll(Collections.singletonList(workItem), TIMEOUT_MS)) {
DBInsertWorkCJ work = (DBInsertWorkCJ) workItem.getResult();
int numUpdates = work.getResult();
}
Ejemplo de Concurrency Utilities for Java EE
Future<Integer> future = executor.submit(
new DBInsertTask("INL", "Falls International Airport"));
int numUpdates = future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
Más opciones al enviar una tarea
Al enviar una tarea, si lo desea, puede asignar un escucha y un tiempo de espera de inicio e indicar si se espera que se ejecute durante mucho tiempo. El tiempo de espera de inicio solo está disponible como parámetro en beans asíncronos, pero para CommonJ y Concurrency Utilities for Java EE se puede implementar un tiempo de espera de inicio en WorkListener o ManagedTaskListener.
Ejemplo de beans asíncronos
long startTimeout = TIMEOUT_MS;
boolean isLongRunning = true;
WorkItem workItem = abWorkManager.startWork(
new DBInsertWorkAB("SGS", "South Saint Paul Municipal Airport"),
startTimeout,
new WorkListenerAB(),
isLongRunning);
ArrayList<WorkItem> items = new
ArrayList<WorkItem>(1);
items.add(workItem);
if (abWorkManager.join(items, WorkManager.JOIN_AND,
Integer.MAX_VALUE)) {
DBInsertWorkAB work = (DBInsertWorkAB) workItem.getResult();
int numUpdates = work.getResult();
}
Ejemplo de CommonJ:
long startTimeout = TIMEOUT_MS;
boolean isLongRunning = true;
DBInsertWorkCJ work = new DBInsertWorkCJ("STP", "Saint Paul Downtown Airport");
work.setDaemon(isLongRunning);
WorkItem workItem = cjWorkManager.schedule(
work, new WorkListenerCJ(work, startTimeout));
Collection<WorkItem> items =
Collections.singleton(workItem);
if (cjWorkManager.waitForAll(items, WorkManager.INDEFINITE)) {
work = (DBInsertWorkCJ) workItem.getResult();
int numUpdates = work.getResult();
}
Ejemplo de Concurrency Utilities for Java EE
long startTimeout = TIMEOUT_MS;
boolean isLongRunning = true;
Callable<Integer> contextualTask = ManagedExecutors.managedTask(
new DBInsertTask("LVN", "Airlake Airport"),
Collections.singletonMap(ManagedTask.LONGRUNNING_HINT,
Boolean.toString(isLongRunning)),
new TaskListener(startTimeout));
Future<Integer> future = executor.submit(contextualTask);
int numUpdates = future.get();
Espera de la finalización de un grupo de tareas
Los tres modelos de programación proporcionan formas para esperar a que se complete un grupo de tareas. Los ejemplos siguientes especifican una cantidad máxima de tiempo para esperar, ya que es posible esperar de forma indefinida o añadir más granularidad en Concurrency Utilities for Java EE invocando de forma secuencial el método get en los distintos valores futuros.
ArrayList<WorkItem> items = new
ArrayList<WorkItem>(3);
items.add(abWorkManager.startWork(
new DBInsertWorkAB("COQ", "Cloquet/Carlton County Airport")));
items.add(abWorkManager.startWork(
new DBInsertWorkAB("CQM", "Cook Municipal Airport")));
items.add(abWorkManager.startWork(
new DBInsertWorkAB("CKN", "Crookston Municipal Airport")));
boolean allCompleted = abWorkManager.join(items,
WorkManager.JOIN_AND, TIMEOUT_MS);
int numUpdates = 0;
for (WorkItem workItem : items) {
if (workItem.getStatus() == WorkEvent.WORK_COMPLETED) {
DBInsertWorkAB work = (DBInsertWorkAB) workItem.getResult();
numUpdates += work.getResult();
} else
((Work) workItem.getEventTrigger(Work.class)).release();
}
Ejemplo de CommonJ:
List<DBInsertWorkCJ> workList = Arrays.asList(
new DBInsertWorkCJ("DTL", "Detroit Lakes Airport"),
new DBInsertWorkCJ("TOB", "Dodge Center Airport"),
new DBInsertWorkCJ("DYT", "Sky Harbor Airport"));
List<WorkItem> items = new
ArrayList<WorkItem>(workList.size());
for (DBInsertWorkCJ work : workList)
items.add(cjWorkManager.schedule(work));
boolean allCompleted = cjWorkManager.waitForAll(items, TIMEOUT_MS);
int numUpdates = 0;
for (int i = 0; i < items.size(); i++) {
WorkItem workItem = items.get(i);
if (workItem.getStatus() == WorkEvent.WORK_COMPLETED) {
DBInsertWorkCJ work = (DBInsertWorkCJ) workItem.getResult();
numUpdates += work.getResult();
} else
workList.get(i).release();
}
Ejemplo de Concurrency Utilities for Java EE
List<DBInsertTask> tasks = Arrays.asList(
new DBInsertTask("CFE", "Buffalo Municipal Airport"),
new DBInsertTask("CHU", "Caledonia-Houston County Airport"),
new DBInsertTask("CBG", "Cambridge Municipal Airport"));
int numUpdates = 0;
List<Future<Integer>> futures =
executor.invokeAll(tasks, TIMEOUT_MS, TimeUnit.MILLISECONDS);
for (Future<Integer> future : futures)
numUpdates += future.get();
Espera de la finalización de una sola tarea dentro de un grupo
Los tres modelos de programación proporcionan formas de espera para que se complete una sola tarea dentro de un grupo. Los ejemplos siguientes especifican una cantidad máxima de tiempo para esperar, pero también es posible esperar de forma indefinida.
Ejemplo de beans asíncronos
ArrayList<WorkItem> items = new
ArrayList<WorkItem>(3);
items.add(abWorkManager.startWork(new PrimeFinderWork(20)));
items.add(abWorkManager.startWork(new PrimeFinderWork(50)));
items.add(abWorkManager.startWork(new PrimeFinderWork(80)));
boolean anyCompleted = abWorkManager.join(items, WorkManager.JOIN_OR, TIMEOUT_MS);
long prime = -1;
for (WorkItem workItem : items) {
if (workItem.getStatus() == WorkEvent.WORK_COMPLETED) {
PrimeFinderWork work = (PrimeFinderWork) workItem.getResult();
prime = work.getPrimeNumber();
} else
((Work) workItem.getEventTrigger(Work.class)).release();
}
Ejemplo de CommonJ:
List<PrimeFinderWork> workList = Arrays.asList(
new PrimeFinderWork(20),
new PrimeFinderWork(50),
new PrimeFinderWork(80));
List<WorkItem> items = new
ArrayList<WorkItem>(workList.size());
for (PrimeFinderWork work : workList)
items.add(cjWorkManager.schedule(work));
Collection<WorkItem> completedItems =
cjWorkManager.waitForAny(items, TIMEOUT_MS);
long prime = -1;
for (int i = 0; i < items.size(); i++) {
WorkItem workItem = items.get(i);
if (completedItems.contains(workItem)) {
PrimeFinderWork work = (PrimeFinderWork)
workItem.getResult();
prime = work.getPrimeNumber();
} else
workList.get(i).release();
}
Ejemplo de Concurrency Utilities for Java EE
List<PrimeFinderTask> tasks = Arrays.asList(
new PrimeFinderTask(20),
new PrimeFinderTask(50),
new PrimeFinderTask(80));
long prime = executor.invokeAny(tasks, TIMEOUT_MS, TimeUnit.MILLISECONDS);
Obtener la excepción de causa cuando falla una tarea
Los tres modelos de programación proporcionan formas para obtener la excepción de causa cuando falla la ejecución de una tarea. Esto se puede realizar con escuchas (se pueden encontrar ejemplos más abajo en esta página) o cuando se obtener el resultado de la tarea, ya sea de WorkItem o Future. Se genera WorkException o ExecutionException, que contiene la excepción original como la causa.
Ejemplo de beans asíncronos
boolean isLongRunning = false;
WorkItem workItem = abWorkManager.startWork(
new DBInsertWorkAB("KADC", "Wadena Municipal Airport"),
isLongRunning);
Throwable exception = null;
ArrayList<WorkItem> items = new
ArrayList<WorkItem>(1);
items.add(workItem);
if (abWorkManager.join(items, WorkManager.JOIN_AND, TIMEOUT_MS))
try {
DBInsertWorkAB work = (DBInsertWorkAB) workItem.getResult();
int numUpdates = work.getResult();
} catch (WorkException x) {
exception = x.getCause();
}
Ejemplo de CommonJ:
boolean isLongRunning = false;
DBInsertWorkCJ work = new DBInsertWorkCJ("KBDH", "Willmar Municipal Airport");
work.setDaemon(isLongRunning);
WorkItem workItem = cjWorkManager.schedule(work);
Throwable exception = null;
if (cjWorkManager.waitForAll(Collections.singleton(workItem),
TIMEOUT_MS))
try {
work = (DBInsertWorkCJ) workItem.getResult();
int numUpdates = work.getResult();
} catch (WorkException x) {
exception = x.getCause();
}
Ejemplo de Concurrency Utilities for Java EE
boolean isLongRunning = false;
Callable<Integer> task = ManagedExecutors.managedTask(
new DBInsertTask("KACQ", "Waseca Municipal Airport"),
Collections.singletonMap(ManagedTask.LONGRUNNING_HINT,
Boolean.toString(isLongRunning)),
null);
Future<Integer> future = executor.submit(task);
Throwable exception = null;
try {
int numUpdates = future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);} catch (ExecutionException x) {
exception = x.getCause();
}
Planificación de una tarea única para ejecutarse después de un intervalo
Los tres modelos de programación proporcionan una forma para planificar una tarea básica para ejecutarse en una hebra agrupada en el mismo punto en el futuro, y obtener el resultado.
Ejemplo de beans asíncronos
AsynchScope asynchScope = abWorkManager.findOrCreateAsynchScope("MyScope");
AlarmManager alarmManager = asynchScope.getAlarmManager();
Alarm alarm = alarmManager.create(
new DBInsertAlarmListener(),
new String[] { "MSP", "Minneapolis-Saint Paul International Airport"},
(int) TimeUnit.SECONDS.toMillis(1));
DBInsertAlarmListener alarmListener = (DBInsertAlarmListener) alarm.getAlarmListener();
// Sondeo para que aparezca el resultado
for (long start = System.nanoTime();
alarmListener.getResult() < 0 && System.nanoTime() -
start < TIMEOUT_NS;
Thread.sleep(200)) ;
int numUpdates = alarmListener.getResult();
Ejemplo de CommonJ:
Timer timer = timerManager.schedule(
new DBInsertTimerListener("STC", "Saint Cloud Regional Airport"),
TimeUnit.SECONDS.toMillis(1));
DBInsertTimerListener timerListener = (DBInsertTimerListener) timer.getTimerListener();
// Sondeo para que aparezca el resultado
for (long start = System.nanoTime();
timerListener.getResult() < 0 && System.nanoTime() - start < TIMEOUT_NS;
Thread.sleep(200)) ;
int numUpdates = timerListener.getResult();
Ejemplo de Concurrency Utilities for Java EE
ScheduledFuture<Integer> future = executor.schedule(
new DBInsertTask("RST", "Rochester International Airport"),
1,
TimeUnit.SECONDS);
int numUpdates = future.get(TIMEOUT_NS, TimeUnit.NANOSECONDS);
Planificación de una tarea periódica a un ritmo fijo y consulta del intervalo hasta la siguiente ejecución
Los modelos de programación de CommonJ y Concurrency Utilities for Java EE proporcionan una forma para planificar una tarea periódica para ejecutarse a un ritmo fijo (por ejemplo, cada hora al inicio de la hora). La planificación en tiempo real no está garantizada. La tarea se puede iniciar en cualquier momento después de este momento, pero no antes. Los modelos de programación de CommonJ y Concurrency Utilities for Java EE también proporcionan un práctico método para calcular el retardo, hasta la siguiente ejecución.
Ejemplo de CommonJ:
Timer timer = timerManager.scheduleAtFixedRate(
new PrimeFinderTimerListener(120),
TimeUnit.MINUTES.toMillis(90),
TimeUnit.MINUTES.toMillis(30));
long nextExecTime = timer.getScheduledExecutionTime();
long delay = TimeUnit.MILLISECONDS.toSeconds(
nextExecTime - System.currentTimeMillis());
Ejemplo de Concurrency Utilities for Java EE
ScheduledFuture<?> future =
executor.scheduleAtFixedRate(
new PrimeFinderRunnable(120), 90, 30, TimeUnit.MINUTES);
long delay = future.getDelay(TimeUnit.SECONDS);
Planificación de una tarea periódica con un retardo fijo entre ejecuciones y cancelación de la tarea
Los modelos de programación de CommonJ y Concurrency Utilities for Java EE proporcionan una forma para planificar una tarea periódica para ejecutarse con un intervalo fijo entre el final de una ejecución y el inicio de la siguiente. La planificación en tiempo real no está garantizada. La tarea se puede iniciar en cualquier momento después de este momento, pero no antes. Los beans asíncronos proporciona un método de restablecimiento en Alarm que pueden utilizar para conseguir el mismo comportamiento. Los tres modelos de programación proporcionan una forma para cancelar el inicio de más ejecuciones de una tarea planificada.
Ejemplo de beans asíncronos
AsynchScope asynchScope =
abWorkManager.findOrCreateAsynchScope("MyScope");
AlarmManager alarmManager = asynchScope.getAlarmManager();
Alarm alarm = alarmManager.create(
new PrimeFinderAlarmListener(90), 50, 10);
// ... al final cancelar la alarma
alarm.cancel();
Ejemplo de CommonJ:
Timer timer = timerManager.schedule(
new PrimeFinderTimerListener(90), 50, 50);
// ... eventually cancel the timer
timer.cancel();
Ejemplo de Concurrency Utilities for Java EE
ScheduledFuture<?> future =
executor.scheduleWithFixedDelay(
new PrimeFinderRunnable(90), 50, 50, TimeUnit.MILLISECONDS);
// ... al final cancelar la tarea
future.cancel(false);
Planificación de una tarea periódica para ejecutarse a distintos intervalos
En los tres modelos de programación es posible calcular con cada ejecución el intervalo que transcurrirá antes de que se repita la siguiente tarea periódica. Los beans asíncronos proporcionan un método de restablecimiento para las alarmas. Concurrency Utilities for Java EE le permite conectar un desencadenante que calcula el siguiente tiempo de ejecución. CommonJ no proporcionada nada de esto, pero en CommonJ y otros modelos de programación, es posible volver a programar la tarea cuando finaliza la ejecución anterior. En los ejemplos siguientes, se planifica una tarea para ejecutarse exactamente cuatro veces, con un retardo distinto antes de cada ejecución. El código para restablecer, volver a programar o calcular la siguiente ejecución se encuentra en el desencadenante incluido en esta sección y las implementaciones AlarmListener y TimerListener, que están incluidas en la sección implementación de tarea básica.
Ejemplo de beans asíncronos
int initialDelay = 50;
int[] subsequentDelays = new int[] { 40, 80, 70 };
AsynchScope asynchScope =
abWorkManager.findOrCreateAsynchScope("MyScope");
AlarmManager alarmManager = asynchScope.getAlarmManager();
Alarm alarm = alarmManager.create(
new PrimeFinderAlarmListener(60),
subsequentDelays,
initialDelay);
Thread.sleep(5000);
PrimeFinderAlarmListener alarmListener =
(PrimeFinderAlarmListener) alarm.getAlarmListener();
long prime = alarmListener.getPrimeNumber();
Ejemplo de CommonJ:
long initialDelay = 50;
long [] subsequentDelays = new long[] { 40, 80, 70 };
Timer timer = timerManager.schedule(
new PrimeFinderTimerListener(60, subsequentDelays),
initialDelay);
Thread.sleep(5000);
PrimeFinderTimerListener timerListener = (PrimeFinderTimerListener)
timer.getTimerListener();
long prime = timerListener.getPrimeNumber();
Ejemplo de Concurrency Utilities for Java EE
ScheduledFuture<Long> future = executor.schedule(
new PrimeFinderTask(60),
new DelayTrigger(50, 40, 80, 70));
Thread.sleep(5000);
long prime = future.get();
public class DelayTrigger implements Trigger {
private int count;
private long[] delays;
volatile boolean isSuspended;
public DelayTrigger(long... delays) {
this.delays = delays;
}
public Date getNextRunTime(LastExecution previousExecution, Date taskScheduledTime) {
if (delays.length > count)
return new Date(System.currentTimeMillis() +
delays[count++]);
else
return null;
}
public boolean skipRun(LastExecution previousExecution, Date scheduledRunTime) {
return isSuspended;
}
}
Suspensión y reanudación de la ejecución de tareas
CommonJ TimerManager proporciona interfaces para suspender y reanudar la ejecución de tareas. Concurrency Utilities for Java EE proporciona esta prestación de una forma más granular a través del método skipRun del mecanismo del desencadenante que se puede conectar. Se puede proporcionar una sola instancia del desencadenante a cualquier número de tareas, siempre que el desencadenante se haya implementado para darle soporte. En el ejemplo siguiente, el desencadenante se ha escrito para utilizarse para la planificación de una sola tarea.
Ejemplo de CommonJ:
Timer timer = timerManager.schedule(
new PrimeFinderTimerListener(100),
new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(5)));
timerManager.suspend();
// ... reanudar en un punto posterior
if (timerManager.isSuspending() || timerManager.isSuspended())
timerManager.resume();
Ejemplo de Concurrency Utilities for Java EE
DelayTrigger trigger = new DelayTrigger(
System.currentTimeMillis() + TimeUnit.DAYS.toMillis(5));
ScheduledFuture<Long> future = executor.schedule(
new PrimeFinderTask(100), trigger);
trigger.isSuspended = true;
// ... reanudar en un punto posterior
if (trigger.isSuspended)
trigger.isSuspended = false;
Detener ejecución adicional de tareas
Los beans asíncronos proporcionan una forma de destruir AsynchScope, que cancela las alarmas creadas por AlarmManagers en dicho ámbito. CommonJ TimerManager proporciona interfaces para detener el inicio de ejecuciones adicionales y esperar a que se detengan todas las tareas en ejecución. Esto es posible porque cada búsqueda de TimerManager genera una instancia nueva, que puede detenerse independientemente de las otras. En Concurrency Utilities for Java EE, se comparte el mismo ManagedScheduledExecutorService entre las búsquedas y las operaciones de ciclo de vida como shutdown, isTerminated y awaitTermination no están autorizadas (por la especificación). Sin embargo, con Concurrency Utilities for Java EE, puede conseguir un comportamiento similar proporcionando ManagedThreadFactory a un ScheduledExecutorService gestionado.
Ejemplo de beans asíncronos
alarmManager.create(
new PrimeFinderAlarmListener(100),
null,
(int) TimeUnit.HOURS.toMillis(1));
alarmManager.create(
new PrimeFinderAlarmListener(200),
null,
(int) TimeUnit.HOURS.toMillis(2));
// ... al final destruir el ámbito asíncrono para cancelar
todas las alarmas
asynchScope.destroy();
Ejemplo de CommonJ:
TimerManager timerManager = (TimerManager) new
InitialContext().lookup(
"java:comp/env/tm/default");
timerManager.schedule(
new PrimeFinderTimerListener(100),
new Date(System.currentTimeMillis() +
TimeUnit.HOURS.toMillis(1)));
timerManager.schedule(
new PrimeFinderTimerListener(200),
new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(2)));
// ... al final detener el gestor de temporizadores
timerManager.stop();
if (!timerManager.isStopped())
timerManager.waitForStop(TIMEOUT_MS);
Ejemplo de Concurrency Utilities for Java EE
ScheduledExecutorService executor =
Executors.newScheduledThreadPool(1, threadFactory);
executor.schedule(new PrimeFinderTask(100), 1, TimeUnit.HOURS);
executor.schedule(new PrimeFinderTask(200), 2, TimeUnit.HOURS);
// .. al final concluir el ejecutor
executor.shutdown();
if (!executor.isTerminated())
executor.awaitTermination(TIMEOUT_MS, TimeUnit.MILLISECONDS);
Construcción de proxies contextuales
Los modelos de programación de beans asíncronos y Concurrency Utilities for Java EE le permiten construir proxies contextuales. El contexto de hebras se captura en la hebra que crea el proxy contextual y se almacena en la misma, aplicándose automáticamente en la hebra de ejecución cuando se invocan métodos de interfaz en el proxy y se elimina de la hebra de ejecución después. Los beans asíncronos proporcionan esto mediante EventSource. Concurrency Utilities for Java EE proporciona esto mediante ContextService.
Ejemplo de beans asíncronos
EventSource eventSource =
abWorkManager.createEventSource();
eventSource.addListener(new DBWriterImpl());
DBWriter dbWriter = (DBWriter) eventSource.getEventTrigger(DBWriter.class);
// puede invocar métodos de interfaz desde cualquier hebra...
int numUpdates = dbWriter.exec(
"INSERT INTO AIRPORTS VALUES(?,?)", "AIT", "Aitkin Municipal Airport");
Ejemplo de Concurrency Utilities for Java EE
DBWriter dbWriter = contextService.createContextualProxy(
new DBWriterImpl(), DBWriter.class);
// puede invocar métodos de interfaz desde cualquier hebra...
int numUpdates = dbWriter.exec(
"INSERT INTO AIRPORTS VALUES(?,?)", "AXN", "Alexandria Municipal Airport");
Construcción de proxies contextuales para varias instancias que se ejecutan en la transacción de la hebra de ejecución
Los beans asíncronos y Concurrency Utilities for Java EE permiten especificar si los métodos de interfaz del proxy del contexto se ejecutan en la transacción de la hebra de ejecución, o si la transacción actual se suspende y se aplica una transacción limpia durante el método. Otra prestación de los beans asíncronos es que permite que un solo proxy desencadene varias instancias de escucha. Sin embargo, Concurrency Utilities for Java EE no tiene esta prestación y se puede conseguir un comportamiento análogo escribiendo un escucha de derivador que delega en varias instancias. En el ejemplo siguiente, invocamos un solo proxy que desencadena varias instancias de escucha, todas bajo la transacción de la hebra que realiza la invocación.
Ejemplo de beans asíncronos:
boolean runInSameTran = true;
EventSource eventSource = abWorkManager.createEventSource();
eventSource.addListener(new DBInsertTask("MKT", "Mankato Regional Airport"));
eventSource.addListener(new DBInsertTask("ULM", "New Ulm Municipal
Airport"));
eventSource.addListener(new DBInsertTask("OWA", "Owatonna Degner Regional Airport"));
Callable<?> eventTrigger = (Callable<?>) eventSource.getEventTrigger(
Callable.class, runInSameTran);
// puede invocar métodos de interfaz desde cualquier hebra...
tran.begin();
try {
eventTrigger.call();
} finally {
tran.commit();
}
Ejemplo de Concurrency Utilities for Java EE
Callable<?> eventTrigger = contextService.createContextualProxy(
new Callable<Void>() {
@Override
public Void call() throws Exception {
new DBInsertTask("FFM", "Fergus Falls Municipal
Airport").call();
new DBInsertTask("ONA", "Winona Municipal Airport").call();
new DBInsertTask("OTG", "Worthington Municipal Airport").call();
return null;
}
},
Collections.singletonMap(ManagedTask.TRANSACTION,
ManagedTask.USE_TRANSACTION_OF_EXECUTION_THREAD),
Callable.class);
// puede invocar métodos de interfaz desde cualquier hebra...
tran.begin();
try {
eventTrigger.call();
} finally {
tran.commit();
}
Creación de tareas contextuales para la ejecución diferida en la hebra de invocación
Los beans asíncronos le permiten crear WorkWithExecutionContext, que, básicamente, es un proxy contextual serializable que, posteriormente, se puede enviar a un WorkManager para ejecutarse bajo el contexto de hebras de la hebra de creación. Si la intención es ejecutarse en la hebra de invocación (método doWork de WorkManager), un proxy contextual puede conseguir un comportamiento análogo en Concurrency Utilities for Java EE.
Ejemplo de beans asíncronos:
WorkWithExecutionContext contextualWork =
abWorkManager.create(
new DBInsertWorkAB("BJI", "Bemidji Regional Airport"));
// se puede ejecutar el trabajo contextual en cualquier hebra...
abWorkManager.doWork(contextualWork);
DBInsertWorkAB work = (DBInsertWorkAB) contextualWork.getWork();
int numUpdates = work.getResult();
Ejemplo de Concurrency Utilities for Java EE
Callable<Integer> contextualTask = contextService.createContextualProxy(
new DBInsertTask("BRD", "Brainerd Lakes Regional Airport"),
Callable.class);
// Se puede ejecutar el proxy contextual en cualquier hebra...
int numUpdates = contextualTask.call();
Creación de tareas contextuales para la ejecución diferida en una hebra agrupada
Los beans asíncronos le permiten crear WorkWithExecutionContext, que, básicamente, es un proxy contextual serializable que, posteriormente, se puede enviar a un WorkManager para ejecutarse bajo el contexto de hebras de la hebra de creación. Si la intención es ejecutarse en una hebra agrupada (método startWork de WorkManager), se puede conseguir un comportamiento análogo en Concurrency Utilities for Java EE enviando un proxy contextual para una tarea a un ejecutor gestionado, que es menos eficiente debido a la duplicación de la propagación y la captura del contexto de hebra.
Ejemplo de beans asíncronos:
WorkWithExecutionContext contextualWork =
abWorkManager.create(
new DBInsertWorkAB("ELO", "Ely Municipal Airport"));
WorkItem workItem = abWorkManager.startWork(contextualWork);
ArrayList<WorkItem> items = new
ArrayList<WorkItem>(1);
items.add(workItem);
if (abWorkManager.join(items, WorkManager.JOIN_AND, TIMEOUT_MS)) {
DBInsertWorkAB work = (DBInsertWorkAB) workItem.getResult();
int numUpdates = work.getResult();
}
Ejemplo de Concurrency Utilities for Java EE
Callable<Integer> contextualTask =
contextService.createContextualProxy(
new DBInsertTask("EVM", "Eveleth-Virginia Municipal Airport"),
Callable.class);
Future<Integer> future = executor.submit(contextualTask);
int numUpdates = future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
Más opciones para tareas contextuales para la ejecución diferida
Al enviar una tarea para la ejecución diferida, si lo desea, puede asignar un escucha y un tiempo de espera de inicio e indicar si se espera que se ejecute durante mucho tiempo. El tiempo de espera de inicio solo está disponible como parámetro en beans asíncronos, pero para CommonJ y Concurrency Utilities for Java EE se puede implementar un tiempo de espera de inicio en WorkListener o ManagedTaskListener.
Ejemplo de beans asíncronos:
long startTimeout = TIMEOUT_MS;
boolean isLongRunning = true;
WorkWithExecutionContext contextualWork = abWorkManager.create(
new DBInsertWorkAB("FRM", "Fairmont Municipal Airport"));
WorkItem workItem = abWorkManager.startWork(
contextualWork, startTimeout, new WorkListenerAB(),
isLongRunning);
ArrayList<WorkItem> items = new
ArrayList<WorkItem>(1);
items.add(workItem);
if (abWorkManager.join(items, WorkManager.JOIN_AND,
Integer.MAX_VALUE)) {
DBInsertWorkAB work = (DBInsertWorkAB) workItem.getResult();
int numUpdates = work.getResult();
}
Ejemplo de Concurrency Utilities for Java EE
long startTimeout = TIMEOUT_MS;
boolean isLongRunning = true;
Callable<Integer> contextualTask =
contextService.createContextualProxy(
new DBInsertTask("FBL", "Faribault Municipal Airport"),
Callable.class);
contextualTask = ManagedExecutors.managedTask(
contextualTask,
Collections.singletonMap(ManagedTask.LONGRUNNING_HINT,
Boolean.toString(isLongRunning)),
new TaskListener(startTimeout));
Future<Integer> future = executor.submit(contextualTask);
int numUpdates = future.get();
Supervisión del subsistema
Los beans asíncronos proporcionan SubsystemMonitor y SubsystemMonitorManager como mecanismo para coordinar entre aplicaciones u otros artefactos para supervisar la disponibilidad. Concurrency Utilities for Java EE no proporciona nada equivalente. Si es necesaria una sustitución para esta prestación, puede hacerlo implementando una aplicación que es conocida para todas las demás aplicaciones que actúa como el equivalente de SubsystemMonitorManager.
Manejo de sucesos
Los beans asíncronos proporcionan la capacidad para registrar escuchas para distintos tipos de sucesos que se producen en AlarmManager, AsynchScope, EventSource, SubsystemMonitor, WorkManager y Work. La mayoría de estos sucesos no tienen ningún equivalente directo en Concurrency Utilities for Java EE. La responsabilidad se deja en manos de las aplicaciones para implementar sus propios mecanismos para sucesos y notificaciones. En un par de casos, Concurrency Utilities for Java EE proporciona una prestación similar. En algunos casos, es posible que tenga que utilizar ManagedTaskListener, que está registrado de una forma más granular (cuando se envía la tarea) en lugar de AlarmManagerEvents y WorkEvents.
Manejo de sucesos para la anomalía que se produce durante la invocación de un proxy contextual
En los beans asíncronos, cuando se utiliza un proxy contextual para invocar una operación y la operación genera una excepción declarada, no se vuelve a notificar la excepción al invocador. En lugar de esto, la excepción se notifica en el suceso listenerExceptionThrown en escuchas EventSourceEvents. En Concurrency Utilities for Java EE, el invocador puede captar la excepción y manejarla.
Ejemplo de beans asíncronos:
EventSource eventSource =
abWorkManager.createEventSource();
eventSource.addListener(new DBWriterImpl());
eventSource.addListener(new EventSourceEvents() {
public void listenerCountChanged(
EventSource es, int oldCount, int newCount) {}
public void listenerExceptionThrown(
EventSource es, Object listener,
String methodName, Throwable exception) {
listenerException.set(exception);
}
public void unexpectedException(
EventSource es, Object runnable, Throwable exception) {}
});
DBWriter dbWriter = (DBWriter)
eventSource.getEventTrigger(DBWriter.class);
// puede invocar métodos de interfaz desde cualquier hebra...
try {
dbWriter.exec(
"INSERT INTO AIRPORTS VALUES(?,?)", "KAUM", "Austin
Municipal Airport");
} catch (Exception x) {
// se espera que esto falle
}
Throwable exception = listenerException.get();
Ejemplo de Concurrency Utilities for Java EE
DBWriter dbWriter = contextService.createContextualProxy(
new DBWriterImpl(), DBWriter.class);
// puede invocar métodos de interfaz desde cualquier hebra...
SQLException exception = null;
try {
dbWriter.exec(
"INSERT INTO AIRPORTS VALUES(?,?)", "KSBU", "Blue Earth Municipal Airport");
} catch (SQLException x) {
exception = x;
}