Migration vers Liberty d'applications utilisant des modèles de programmation avec accès concurrent et asynchrone
Vous pouvez migrer des applications qui utilisent des beans Concurrency Utilities for Java™ EE, Asynchronous Beans, CommonJ Timer et Work Manager depuis WebSphere Application Server traditional vers WebSphere Application Server Liberty.
Asynchronous Beans, CommonJ Timer et Work Manager ne sont pas disponibles dans Liberty. Lors de la migration vers Liberty, les applications doivent basculer vers le modèle de programmation Concurrency Utilities for Java EE. Pour plus d'informations, voir Exemple de tâches d'API implémentant Concurrency Utilities for Java EE.
Différences dans la configuration et l'utilisation d'unités d'exécution
WebSphere Application Server traditional fournit un certain nombre d'options de configuration pour Concurrency Utilities for Java EE concernant la mise en pool des unités d'exécution, qui ne sont pas disponibles dans Liberty. Liberty utilise un seul pool d'unités d'exécution commun à tous les programmes d'exécution gérés et à tous les programmes d'exécution planifiés gérés qui sont également partagés par les composants Liberty. Ceci permet à Liberty d'optimiser la gestion des unités d'exécution. Dans WebSphere Application Server traditional, chaque gestionnaire de travaux peut être configuré avec deux pools d'unités d'exécution. Un des pools est destiné aux tâches soumises pour exécution le plus tôt possible (méthodes submit/execute/invoke de programme d'exécution géré) et comporte une file d'attente de demandes configurable et une action à engager quand la capacité de la file d'attente est dépassée. L'autre pool est destiné aux tâches planifiées (méthodes schedule de programme d'exécution planifié géré).
Si vous comptez utiliser Concurrency Utilities for Java EE avec des pools d'unités d'exécution séparés dans Liberty, vous pouvez envisager plusieurs approches pour aboutir à un comportement similaire à celui des options de configuration disponibles dans WebSphere Application Server traditional.
Construction d'un programme d'exécution Java SE autour d'une fabrique d'unités d'exécution gérée
Le package java.util.concurrent de Java SE permet de construire de plusieurs manières des pools d'unités d'exécution en tant que programmes d'exécution et programmes d'exécution planifiés autour d'une fabrique d'unités d'exécution spécifique. Une fabrique d'unités d'exécution gérée peut être fournie à la place d'une fabrique d'unités d'exécution non gérée, de sorte à disposer d'un pool d'unités d'exécution réalisant des tâches sur des unités d'exécution gérées. Contrairement au programme d'exécution géré et au programme d'exécution planifié géré, les unités d'exécution gérées mises en pool par ces programmes opèrent avec le contexte d'unité d'exécution obtenu lors de la recherche de la fabrique d'unités d'exécution gérée et non pas le contexte lors de la soumission ou la planification de la tâche. Le contexte d'unité d'exécution perdure également sur l'unité d'exécution pendant toute sa durée de vie, ce qui réduit la surcharge due au changement de contexte.
Exemple de remplacement pour maximum d'unités d'exécution de travaux et configuration de file d'attente de travaux
int minThreads = 1;
int maxThreads = 2;
int workRequestQueueSize = 3;
RejectedExecutionHandler workRequestQueueFullAction =
new ThreadPoolExecutor.AbortPolicy();
ManagedThreadFactory threadFactory =
(ManagedThreadFactory) new InitialContext().lookup(
"java:comp/DefaultManagedThreadFactory");
ExecutorService executor = new ThreadPoolExecutor(
minThreads, // similar, but not exact match for coreSize
maxThreads, keepAliveTime, keepAliveTimeUnit,
new ArrayBlockingQueue<Runnable>(workRequestQueueSize),
threadFactory,
workRequestQueueFullAction);
Callable<Integer> task = new MyTask();
Future<Integer> future = executor.submit(task);
int result = future.get();
Exemple de remplacement pour maximum d'unités d'exécution d'alarme
int maxAlarms = 2;
ManagedThreadFactory threadFactory =
(ManagedThreadFactory) new InitialContext().lookup(
"java:comp/DefaultManagedThreadFactory");
ScheduledExecutorService executor =
Executors.newScheduledThreadPool(maxAlarms, threadFactory);
Callable<Integer> task = new MyTask();
ScheduledFuture<Integer> future = executor.schedule(
task, 50, TimeUnit.SECONDS);
int result = future.get();
Application d'une expiration de délai de travail
WebSphere Application Server traditional vous permet de configurer une expiration de délai de travail s'appliquant aux tâches soumises pour exécution dès que possible (méthodes submit/execute/invoke). Si une tâche s'exécute plus longtemps que le délai imparti, une tentative est effectuée pour l'annuler en l'interrompant. Bien que Liberty ne dispose pas d'une option de configuration pour spécifier un tel délai, un comportement similaire peut être implémenté en soumettant la tâche avec un programme d'écoute de tâche gérée qui, en réponse à la notification taskStarting, planifie une tâche pour annuler une tâche Future. Vous pouvez également lors de l'utilisation d'un programme d'exécution de pool d'unités d'exécution, comme dans l'exemple précédent, où un programme d'écoute de tâche gérée n'est pas disponible, prévaloir sur la méthode beforeExecute du programme d'exécution du pool d'unités d'exécution en planifiant une tâche pour interrompre l'unité d'exécution.
Exemple de remplacement d'une expiration de délai de travail
ManagedExecutorService executor =
(ManagedExecutorService) new InitialContext().lookup(
"java:comp/DefaultManagedExecutorService");
Callable<Long> slowTask = new SlowTask();
slowTask = ManagedExecutors.managedTask(
slowTask, new WorkTimeout(5, TimeUnit.SECONDS));
Future<Long> future = executor.submit(slowTask);
try {
long result = future.get(1, TimeUnit.MINUTES);
// task successful...
} catch (CancellationException x) {
// task was canceled, possibly due to timeout
}
public class WorkTimeout implements ManagedTaskListener {
private final long timeout;
private final TimeUnit unit;
public WorkTimeout(long timeout, TimeUnit unit) {
this.timeout = timeout;
this.unit = unit;
}
public void taskSubmitted(Future<?> future,
ManagedExecutorService executor, Object task) {}
public void taskStarting(final Future<?> future,
ManagedExecutorService executor, Object task) {
try {
ScheduledExecutorService scheduledExecutor =
(ScheduledExecutorService) new InitialContext().lookup(
"java:comp/DefaultManagedScheduledExecutorService");
scheduledExecutor.schedule(new Runnable() {
@Override
public void run() {
if (!future.isDone())
future.cancel(true);
}
}, timeout, unit);
} catch (NamingException x) {
x.printStackTrace(System.out);
}
}
public void taskAborted(Future<?> future, ManagedExecutorService executor, Object task, Throwable x) {}
public void taskDone(Future<?> future, ManagedExecutorService executor, Object task, Throwable x) {}
}