Exemple de tâches d'API implémentant Concurrency Utilities for Java EE
Vous pouvez migrer des applications qui utilisent les API Asynchronous beans, CommonJ Timer et Work Manager pour utiliser Concurrency Utilities for Java™ EE.
Concurrency Utilities for Java EE fournit une approche standardisée pour la réalisation d'opérations simultanées dans un serveur d'application. Il remplace les modèles de programmation pour Asynchronous beans, CommonJ Timer et Work Manager.
- Ressources utilisées dans les exemples de code
- Implémentation de tâche de base
- Soumission d'une tâche
- Attente de l'achèvement d'un groupe de tâches
- Attente de l'achèvement d'une tâche isolée dans un groupe
- Obtention de l'exception source de l'échec d'une tâche
- Planification de l'exécution d'une tâche ponctuelle après un intervalle
- Planification d'une tâche répétitive à une cadence fixe et obtention de l'intervalle jusqu'à la prochaine exécution
- Planification de l'exécution d'une tâche répétitive à des intervalles différents
- Suspension et reprise de l'exécution de tâches
- Abolition de l'exécution ultérieure de tâches
- Construction de proxies contextuels
- Construction de proxies contextuels pour plusieurs instances s'exécutant dans la transaction de l'unité d'exécution
- Création de tâches contextuelles pour exécution différée sur l'unité d'exécution appelante
- Options supplémentaires pour tâches contextuelles d'exécution différée
- Surveillance du sous-système
- Traitement d'événement
- Traitement d'événement pour échec se produisant lors de l'appel d'un proxy contextuel
Ressources utilisées dans les exemples de code
Les exemples de code de cette page supposent que les ressources suivantes ont été injectées ou recherchées par l'application :
@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;
Implémentation de tâche de base
Cette section fournit quelques exemples d'implémentations de tâches simples qui sont utilisées par les autres exemples dans le reste de ce document. Asynchronous Beans requiert une interface séparée, AlarmListener, pour les tâches planifiées pour leur exécution dans le futur. CommonJ Beans requiert une interface séparée, TimerListener, pour les tâches planifiées pour leur exécution dans le futur. Les tâches Concurrency Utilities for Java EE peuvent être Runnable (Eéxcutables) ou Callable (Appelables) et permettent d'utiliser l'une ou l'autre interface, qu'une tâche soit soumise pour exécution immédiate ou planifiée pour une exécution ultérieure. Dans certains cas, il est possible de soumettre à un programme d'exécution géré des appels Asynchronous Beans ou CommonJ Work en tant que Runnable (Exécutable) sans aucune modification. La méthode de travail release est remplacée par la possibilité pour les programmes d'exécution d'annuler ou d'interrompre des unités d'exécution en opération. La méthode de travail isDaemon est remplacée par la propriété d'exécution LONGRUNNING_HINT.
Exemple : tâche Work pour Asynchronous beans et CommonJ qui identifie le prochain nombre premier :
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();
}
}
Exemple : tâche AlarmListener pour Asynchronous beans qui identifie le prochain nombre premier :
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();
}
Exemple : tâche TimerListener pour Asynchronous beans qui identifie le prochain nombre premier :
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();
}
}
Exemple de tâche Runnable pour Concurrency Utilities for Java EE qui recherche le nombre premier suivant :
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();
}
}
Exemple de tâche Callable pour Concurrency Utilities for Java EE qui recherche le nombre premier suivant :
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++;
}
}
Exemple : tâche Work Asynchronous Beans réalisant une insertion de base dans la base de données :
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;
}
}
}
}
Exemple : tâche AlarmListener Asynchronous réalisant une insertion de base dans la base de données :
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);
}
}
}
Exemple : tâche Work de CommonJ réalisant une insertion de base dans la base de données :
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;
}
}
}
Exemple : tâche TimerListener de CommonJ réalisant une insertion de base dans la base de données :
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);
}
}
}
Exemple de tâche Callable pour Concurrency Utilities for Java EE qui effectue une insertion de base de données de base :
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();
}
}
}
Soumission d'une tâche
Les trois modèles de programmation permettent de soumettre une tâche de base s'exécutant sur une unité d'exécution d'un pool et d'obtenir son résultat.
Exemple Asynchronous Beans :
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();
}
Exemple 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();
}
Exemple Concurrency Utilities for Java EE :
Future<Integer> future = executor.submit(
new DBInsertTask("INL", "Falls International Airport"));
int numUpdates = future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
Options supplémentaires lors de la soumission d'une tâche
Lors de la soumission d'une tâche, vous pouvez affecter un programme d'écoute et un délai d'attente du démarrage et indiquer si elle est censée durer longtemps. Le délai d'attente au démarrage est disponible uniquement comme paramètres dans Asynchronous beans, mais pour CommonJ et Concurrency Utilities for Java EE il est possible d'implémenter un délai d'attente au démarrage dans WorkListener ou ManagedTaskListener.
Exemple Asynchronous Beans :
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();
}
Exemple 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();
}
Exemple 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();
Attente de l'achèvement d'un groupe de tâches
Les trois modèles de programmation permettent de patienter jusqu'à l'achèvement d'un groupe de tâches. Les exemples suivants spécifient une durée d'attente maximale vu qu'il est possible d'attendre indéfiniment ou d'ajouter encore plus de granularité dans Concurrency Utilities for Java EE en appelant séquentiellement Get sur les divers éléments Futures.
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();
}
Exemple 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();
}
Exemple 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();
Attente de l'achèvement d'une tâche isolée dans un groupe
Les trois modèles de programmation permettent de patienter jusqu'à l'achèvement d'une tâche isolée dans un groupe de tâches. Les exemples suivants spécifient une durée d'attente maximale, mais il est aussi possible d'attendre indéfiniment.
Exemple Asynchronous Beans :
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();
}
Exemple 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();
}
Exemple 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);
Obtention de l'exception source de l'échec d'une tâche
Les trois modèles fournissent des moyens permettant d'obtenir l'exception source en cas d'échec de la tâche. Ceci peut être réalisé à l'aide de programmes d'écoute (des exemples figurent plus loin sur la page) ou, lors de l'obtention du résultat de la tâche, depuis WorkItem ou depuis Future. Une exception WorkException ou ExecutionException est renvoyée et contient l'exception d'origine comme cause.
Exemple Asynchronous Beans :
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();
}
Exemple 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();
}
Exemple 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();
}
Planification de l'exécution d'une tâche ponctuelle après un intervalle
Les trois modèles permettent de planifier l'exécution ultérieure d'une tâche de base sur une unité d'exécution et d'obtenir son résultat.
Exemple Asynchronous Beans :
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();
// Poll for result to appear
for (long start = System.nanoTime();
alarmListener.getResult() < 0 && System.nanoTime() - start < TIMEOUT_NS;
Thread.sleep(200)) ;
int numUpdates = alarmListener.getResult();
Exemple CommonJ :
Timer timer = timerManager.schedule(
new DBInsertTimerListener("STC", "Saint Cloud Regional Airport"),
TimeUnit.SECONDS.toMillis(1));
DBInsertTimerListener timerListener = (DBInsertTimerListener) timer.getTimerListener();
// Poll for result to appear
for (long start = System.nanoTime();
timerListener.getResult() < 0 && System.nanoTime() - start < TIMEOUT_NS;
Thread.sleep(200)) ;
int numUpdates = timerListener.getResult();
Exemple 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);
Planification d'une tâche répétitive à une cadence fixe et obtention de l'intervalle jusqu'à la prochaine exécution
Les modèles de programmation CommonJ et Concurrency Utilities for Java EE permettent de planifier l'exécution d'une tâche répétitive à une cadence fixe (par exemple, au début de chaque heure). La planification en temps réel n'est pas garantie. La tâche peut démarrer à n'importe quel moment après cette date, mais non pas plus tôt. Les modèles de programmation CommonJ et Concurrency Utilities for Java EE fournissent également une méthode de simplification du calcul du délai d'attente jusqu'à la prochaine exécution.
Exemple 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());
Exemple Concurrency Utilities for Java EE :
ScheduledFuture<?> future = executor.scheduleAtFixedRate(
new PrimeFinderRunnable(120), 90, 30, TimeUnit.MINUTES);
long delay = future.getDelay(TimeUnit.SECONDS);
Planification d'une tâche répétitive avec un délai fixe entre les exécutions et annulation de la tâche
Les modèles de programmation CommonJ et Concurrency Utilities for Java EE permettent de planifier l'exécution d'une tâche répétitive avec un intervalle fixe entre la fin d'une exécution et le lancement de la suivante. La planification en temps réel n'est pas garantie. La tâche peut démarrer à n'importe quel moment après cette date, mais non pas plus tôt. Asynchronous beans offre une méthode de réinitialisation d'Alarm pouvant être utilisée pour obtenir le même comportement. Les trois modèles de programmation permettent d'annuler le lancement ultérieur d'une tâche planifiée.
Exemple Asynchronous Beans :
AsynchScope asynchScope = abWorkManager.findOrCreateAsynchScope("MyScope");
AlarmManager alarmManager = asynchScope.getAlarmManager();
Alarm alarm = alarmManager.create(
new PrimeFinderAlarmListener(90), 50, 10);
// ... eventually cancel the alarm
alarm.cancel();
Exemple CommonJ :
Timer timer = timerManager.schedule(
new PrimeFinderTimerListener(90), 50, 50);
// ... eventually cancel the timer
timer.cancel();
Exemple Concurrency Utilities for Java EE :
ScheduledFuture<?> future = executor.scheduleWithFixedDelay(
new PrimeFinderRunnable(90), 50, 50, TimeUnit.MILLISECONDS);
// ... eventually cancel the task
future.cancel(false);
Planification d'une tâche répétitive pour son exécution à des intervalles différents
Il est possible dans les trois modèles de programmation de calculer à chaque exécution l'intervalle après lequel une tâche répétitive se reproduira. Asynchronous beans offre une méthode de réinitialisation des alarmes. Concurrency Utilities for Java EE vous permet d'intégrer un déclencher qui calcule l'heure de la prochaine exécution. CommonJ ne fournit aucune de ces deux méthodes, mais comme dans d'autres modèles de programmation, il est possible de replanifier la tâche lorsque l'exécution précédente s'achève. Dans les exemples suivants, une tâche est planifiée pour s'exécuter exactement quatre fois, avec un décalage différent entre chaque exécution. Le code pour réinitialiser, replanifier ou calculer la prochaine exécution figure dans le déclencheur inclus dans cette section et dans les implémentations AlarmListener et TimerListener incluses dans la section Implémentation de tâche de base.
Exemple Asynchronous Beans :
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();
Exemple 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();
Exemple 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;
}
}
Suspension et reprise de l'exécution de tâches
CommonJ TimerManager fournit des interfaces pour suspendre et reprendre l'exécution de tâches. Concurrency Utilities for Java EE fournit cette capacité sur une base plus granulaire via la méthode skipRun du mécanisme intégrable Trigger. Une seule instance Trigger peut être soumise pour un nombre quelconque de tâches, dans la mesure où ce mécanisme est implémenté pour cette prise en charge. Dans l'exemple suivant, le mécanisme Trigger est rédigé pour la planification d'une seule tâche.
Exemple CommonJ :
Timer timer = timerManager.schedule(
new PrimeFinderTimerListener(100),
new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(5)));
timerManager.suspend();
// ... resume at a later point
if (timerManager.isSuspending() || timerManager.isSuspended())
timerManager.resume();
Exemple 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;
// ... resume at a later point
if (trigger.isSuspended)
trigger.isSuspended = false;
Abolition de l'exécution ultérieure de tâches
Asynchronous beans permet de supprimer l'élément AsynchScope, ce qui annule toutes les alarmes créées par les gestionnaires AlarmManagers dans cette portée. CommonJ TimerManager fournit des interfaces pour empêcher le lancement d'autres exécutions et pour attendre l'arrêt de toutes celles en exécution. Ceci est possible car chaque recherche de TimerManager produit une nouvelle instance, qui peut être arrêtée indépendamment des autres. Dans Concurrency Utilities for Java EE, le même service ManagedScheduledExecutorService est partagé entre les recherches et les opérations de cycle de vie comme shutdown, isTerminated et awaitTermination ne sont pas autorisées (conformément à la spécification). Toutefois, Concurrency Utilities for Java EE permet d'obtenir un comportement similaire en fournissant une fabrique ManagedThreadFactory à un service ScheduledExecutorService non géré.
Exemple Asynchronous Beans :
alarmManager.create(
new PrimeFinderAlarmListener(100),
null,
(int) TimeUnit.HOURS.toMillis(1));
alarmManager.create(
new PrimeFinderAlarmListener(200),
null,
(int) TimeUnit.HOURS.toMillis(2));
// ... eventually destroy the asynch scope to cancel all alarms
asynchScope.destroy();
Exemple 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)));
// ... eventually stop the timer manager
timerManager.stop();
if (!timerManager.isStopped())
timerManager.waitForStop(TIMEOUT_MS);
Exemple 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);
// .. eventually shut down the executor
executor.shutdown();
if (!executor.isTerminated())
executor.awaitTermination(TIMEOUT_MS, TimeUnit.MILLISECONDS);
Construction de proxies contextuels
Les modèles de programmation Asynchronous beans et Concurrency Utilities for Java EE vous permettent de construire des proxies contextuels. Le contexte d'unité d'exécution est capturé depuis celle qui crée le proxy contextuel et stocké dans celle-ci, étant appliqué automatiquement à l'unité d'exécution lorsque les méthodes d'interface sont appelées sur le proxy et supprimé ensuite de l'unité d'exécution. Asynchronous beans fournit ceci via EventSource. Concurrency Utilities for Java EE fournit ceci via ContextService.
Exemple Asynchronous Beans :
EventSource eventSource = abWorkManager.createEventSource();
eventSource.addListener(new DBWriterImpl());
DBWriter dbWriter = (DBWriter) eventSource.getEventTrigger(DBWriter.class);
// Can invoke interface methods from any thread...
int numUpdates = dbWriter.exec(
"INSERT INTO AIRPORTS VALUES(?,?)", "AIT", "Aitkin Municipal Airport");
Exemple Concurrency Utilities for Java EE :
DBWriter dbWriter = contextService.createContextualProxy(
new DBWriterImpl(), DBWriter.class);
// Can invoke interface methods from any thread...
int numUpdates = dbWriter.exec(
"INSERT INTO AIRPORTS VALUES(?,?)", "AXN", "Alexandria Municipal Airport");
Construction de proxies contextuels pour plusieurs instances s'exécutant dans la transaction de l'unité d'exécution
Asynchronous Beans et Concurrency Utilities for Java EE permettent tous deux de spécifier si les méthodes d'interface du proxy de contexte sont exécutées dans la transaction de l'unité d'exécution ou si la transaction actuelle est suspendue et qu'un nouveau contexte de transaction est appliqué pendant la méthode. Par ailleurs, Asynchronous Beans permet à plusieurs instances de programme d'écoute d'être déclenchées par un même proxy. Par contre, Concurrency Utilities for Java EE ne dispose pas de cette capacité, mais vous pouvez obtenir un résultat analogue en rédigeant un programme d'écoute encapsuleur qui délègue à plusieurs autres instances. Dans l'exemple suivant, un seul proxy est appelé et déclenche plusieurs instances de programme d'écoute, toutes sous la transaction de l'unité d'exécution appelante.
Exemple Asynchronous Beans :
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);
// Can invoke interface methods from any thread...
tran.begin();
try {
eventTrigger.call();
} finally {
tran.commit();
}
Exemple 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);
// Can invoke interface methods from any thread...
tran.begin();
try {
eventTrigger.call();
} finally {
tran.commit();
}
Création de tâches contextuelles pour exécution différée sur l'unité d'exécution appelante
Asynchronous Beans vous permet de créer un élément WorkWithExecutionContext, qui est essentiellement un proxy contextuel sérialisable pour une tâche et qui peut ensuite être soumis à un WorkManager pour s'exécuter sous le contexte d'unité d'exécution de l'unité d'exécution créatrice. Si l'intention est une exécution sous l'unité d'exécution appelante (méthode doWork de WorkManager), un proxy contextuel peut accomplir un comportement analogue dans Concurrency Utilities for Java EE.
Exemple Asynchronous Beans :
WorkWithExecutionContext contextualWork = abWorkManager.create(
new DBInsertWorkAB("BJI", "Bemidji Regional Airport"));
// Can run the contextual work on any thread...
abWorkManager.doWork(contextualWork);
DBInsertWorkAB work = (DBInsertWorkAB) contextualWork.getWork();
int numUpdates = work.getResult();
Exemple Concurrency Utilities for Java EE :
Callable<Integer> contextualTask = contextService.createContextualProxy(
new DBInsertTask("BRD", "Brainerd Lakes Regional Airport"),
Callable.class);
// Can run the contextual proxy on any thread...
int numUpdates = contextualTask.call();
Création de tâches contextuelles pour exécution différée sur une unité d'exécution d'un pool
Asynchronous Beans vous permet de créer un élément WorkWithExecutionContext, qui est essentiellement un proxy contextuel sérialisable pour une tâche et qui peut ensuite être soumis à un WorkManager pour s'exécuter sous le contexte d'unité d'exécution de l'unité d'exécution créatrice. Si l'objectif est qu'il s'exécute dans une unité d'exécution de pool (méthode startWork de WorkManager), un comportement analogue peut être obtenu dans Concurrency Utilities for Java EE en soumettant un proxy contextuel pour une tâche à un programme d'exécution géré, ce qui est moins efficace en raison de la duplication de la capture et de la propagation du contexte d'unité d'exécution.
Exemple Asynchronous Beans :
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();
}
Exemple 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);
>Options supplémentaires pour tâches contextuelles d'exécution différée
Lors de la soumission d'une tâche pour exécution différée, vous pouvez affecter un programme d'écoute et un délai d'attente du démarrage et indiquer si elle est censée durer longtemps. Le délai d'attente au démarrage est disponible uniquement comme paramètres dans Asynchronous beans, mais pour CommonJ et Concurrency Utilities for Java EE il est possible d'implémenter un délai d'attente au démarrage dans WorkListener ou ManagedTaskListener.
Exemple Asynchronous Beans :
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();
}
Exemple 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();
Surveillance du sous-système
Asynchronous Beans fournit le mécanisme SubsystemMonitor et SubsystemMonitorManager pour coordination entre applications ou autres artefacts pour suivi de la disponibilité. Concurrency Utilities for Java EE ne fournit aucune solution équivalente. Si vous avez néanmoins besoin de cette capacité, vous pouvez implémenter une application connue de toutes les autres et qui fait fonction d'équivalent de SubsystemMonitorManager.
Traitement des événements
Asynchronous Beans permet d'enregistrer des programmes d'écoute pour divers types d'événement se produisant sur AlarmManager, AsynchScope, EventSource, SubsystemMonitor, WorkManager et Work. La plupart de ces événements n'ont pas d'équivalents directs dans Concurrency Utilities for Java EE. Il incombe donc aux applications d'implémenter leurs propres mécanismes pour les événements et les notifications. Dans un ou deux cas, Concurrency Utilities for Java EE fournit une fonction similaire. Dans certains cas, vous pourriez éventuellement utiliser ManagedTaskListener, lequel est enregistré sur une base plus granulaire (lors de la soumission de la tâche), à la place de AlarmManagerEvents et WorkEvents.
Traitement d'événement en cas d'échec se produisant lors de l'appel d'un proxy contextuel
Dans Asynchronous Beans, lorsqu'un proxy contextuel est utilisé pour appeler une opération et que celle-ci génère une exception déclarée, l'exception n'est pas signalée à l'appelant. Au lieu de cela, l'exception est signalée sur l'événement listenerExceptionThrown aux programmes d'écoute EventSourceEvents. Dans Concurrency Utilities for Java EE, l'appelant peut intercepter l'exception et la traiter.
Exemple Asynchronous Beans :
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);
// Can invoke interface methods from any thread...
try {
dbWriter.exec(
"INSERT INTO AIRPORTS VALUES(?,?)", "KAUM", "Austin Municipal Airport");
} catch (Exception x) {
// expecting this to fail
}
Throwable exception = listenerException.get();
Exemple Concurrency Utilities for Java EE :
DBWriter dbWriter = contextService.createContextualProxy(
new DBWriterImpl(), DBWriter.class);
// Can invoke interface methods from any thread...
SQLException exception = null;
try {
dbWriter.exec(
"INSERT INTO AIRPORTS VALUES(?,?)", "KSBU", "Blue Earth Municipal Airport");
} catch (SQLException x) {
exception = x;
}