Ejemplos de la migración a EE Concurrency desde beans asíncronos y CommonJ

Puede migrar las aplicaciones que utilizan beans asíncronos y las API de gestor de trabajo y temporizador CommonJ para que utilicen Concurrency Utilities for Java™ EE.

Concurrency Utilities for Java EE proporciona un método estandarizado para realizar operaciones simultáneas en un servidor de aplicaciones. Sustituye a los modelos de programación de los beans asíncronos y el gestor de trabajo y temporizador CommonJ. Los ejemplos de código de esta página muestran cómo migrar aplicaciones existentes para utilizar Concurrency Utilities for Java EE.

Deprecated feature Deprecated feature: Los beans asíncronos y las API CommonJ están en desuso.depfeat

Recursos utilizados en los ejemplos de código

Los ejemplos de código de esta página presuponen que en la aplicación se han 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 una tarea básica

En esta sección se proporcionan algunos ejemplos de implementaciones de tarea simple que utilizan los otros ejemplos durante el resto de este documento. Los beans asíncronos requieren una interfaz aparte, AlarmListener, para las tareas planificadas para ejecutarse en el futuro. CommonJ requiere una interfaz aparte, TimerListener, para las tareas planificadas para ejecutarse en el futuro. Las tareas de Concurrency Utilities for Java EE pueden ser Runnable o Callable, y se puede utilizar cualquiera de las dos interfaces, independientemente de si una tarea se envía para su ejecución inmediata o si está planificada para ejecutarse en el futuro. En algunos casos, es posible enviar beans asíncronos o trabajo CommonJ como Runnable a un ejecutor gestionado sin cambios. El método release de trabajo se sustituye por la capacidad de los ejecutores gestionados de cancelar e interrumpir las hebras en ejecución. El método isDaemon de trabajo se sustituye con la propiedad de ejecución LONGRUNNING_HINT.

Tarea Work de ejemplo para beans asíncronos y 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 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();
    }
}

Ejemplos 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 de 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 que 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 manera de enviar una tarea básica para su ejecución 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);

Opciones adicionales para el envío de una tarea

Al enviar una tarea, opcionalmente puede asignar un escucha y tiempo de espera de inicio e indicar si se espera que la ejecución dure mucho tiempo. El tiempo de espera de inicio sólo está disponible como un parámetro en beans asíncronos, pero para CommonJ and 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();

En espera de finalización de un grupo de tareas

Los tres modelos de programación proporcionan formas de esperar la finalización de un grupo de tareas. Los ejemplos siguientes especifican una cantidad máxima de tiempo que se esperará. Es posible esperar indefinidamente o utilizar Concurrency Utilities for Java EE para ejecutar get secuencialmente en las variables future.

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();

En espera de finalización de una única tarea de un grupo

Los tres modelos de programación proporcionan formas de esperar la finalización de una sola tarea en un grupo. Los ejemplos siguientes especifican una cantidad máxima de tiempo que se esperará, pero también es posible esperar indefinidamente.

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);

Obtención de la causa de excepción cuando una tarea falla

Los tres modelos de programación proporcionan formas de obtener la causa de la excepción cuando la ejecución de una tarea falla. Esto se puede hacer con escuchas (puede encontrar ejemplos posteriormente en esta página) o al obtener el resultado de la tarea, de WorkItem o Future. Se emite 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 de un solo uso para ejecutarla tras un intervalo

Los tres modelos de programación proporcionan una manera de planificar una tarea básica para su ejecución en una hebra agrupada en algún momento 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();
// 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();

Ejemplo de 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();

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 repetitiva con una frecuencia fija y consulta del intervalo hasta la siguiente ejecución

Los modelos de programación de CommonJ y Concurrency Utilities for Java EE proporcionan una manera de planificar una tarea repetitiva para su ejecución con una frecuencia fija (por ejemplo, cada hora al inicio de la hora). La planificación en tiempo real no está garantizada. La tarea puede iniciarse 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 cómodo 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 repetitiva 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 manera de planificar una tarea repetitiva para su ejecución 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 puede iniciarse en cualquier momento después de este momento, pero no antes. Los beans asíncronos proporcionan un método de restablecimiento en Alarm que se puede utilizar para conseguir el mismo comportamiento. Los tres modelos de programación proporcionan una manera de cancelar el inicio de ejecuciones adicionales en 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);
// ... eventually cancel the alarm
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);
// ... eventually cancel the task
future.cancel(false);

Planificación de una tarea repetitiva para ejecutarla a intervalos variables

Es posible en los tres modelos de programación calcular con cada ejecución el intervalo transcurrido el cual se repite la próxima vez una tarea repetitiva. Los beans asíncronos proporcionan un método de restablecimiento para alarmas. Concurrency Utilities for Java EE le permite conectar un desencadenante que calcula la siguiente hora de ejecución. CommonJ no los proporciona, pero en CommonJ y otros modelos de programación es posible volver a planificar la tarea cuando se complete la ejecución anterior. En los ejemplos siguientes, una tarea se planifica para ejecutarse exactamente cuatro veces, con un retardo distinto antes de cada ejecución. El código para restablecer, volver a planificar o calcular la siguiente ejecución se encuentra en el desencadenante incluido en esta sección y las implementaciones AlarmListener y TimerListener, que se incluyen en la sección Implementación de una 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 capacidad de forma más granular mediante el método skipRun del mecanismo de desencadenante conectable. Se puede proporcionar una única instancia de desencadenante a cualquier número de tareas, siempre que se implemente el desencadenante para darle soporte. En el ejemplo siguiente, el desencadenante se ha escrito para su utilización para volver a planificar una única tarea.

Ejemplo de 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();

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;
// ... resume at a later point
if (trigger.isSuspended)
    trigger.isSuspended = false;

Detención de la ejecución adicional de tareas

Los beans asíncronos proporcionan una manera de destruir AsynchScope, que cancela todas las alarmas creadas por AlarmManagers en dicho ámbito. CommonJ TimerManager proporciona interfaces para detener el inicio de ejecuciones adicionales y esperar la detención de todas las tareas en ejecución. Esto es posible porque cada búsqueda de un TimerManager produce una nueva instancia, que puede detenerse independientemente de las otras. En Concurrency Utilities for Java EE, el mismo ManagedScheduledExecutorService se comparte entre búsquedas y las operaciones de ciclo de vida como shutdown, isTerminated y awaitTermination no se permiten (por espec.). Sin embargo, con Concurrency Utilities for Java EE, puede conseguir un comportamiento similar proporcionando un ManagedThreadFactory a un ScheduledExecutorService no 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));
// ... eventually destroy the asynch scope to cancel all alarms
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)));
// ... eventually stop the timer manager
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);
// .. eventually shut down the executor
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 hebra se captura de la hebra que crea el proxy contextual y se almacena en ella, se aplica automáticamente a la hebra de ejecución cuando se invocan métodos de interfaz en el proxy y se elimina de la hebra de ejecución posteriormente. 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 en ejecución en la transacción de la hebra de ejecución

Los beans asíncronos y Concurrency Utilities for Java EE le permiten especificar si se ejecutan métodos de interfaz del proxy de contexto en la transacción de la hebra de ejecución, o si la transacción actual se suspende y se aplica un contexto de transacción limpia durante el método. Otra capacidad de los beans asíncronos es que permite que un solo proxy desencadenen varias instancias de desencadenante. Sin embargo, Concurrency Utilities for Java EE carece de esta capacidad y se puede obtener el comportamiento análogo escribiendo un escucha de envoltura que delega en varios otros. El ejemplo siguiente invoca un único proxy que desencadena varias instancias de escucha, todas ellas bajo de la transacción de la hebra de 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 para una tarea, que se puede enviar posteriormente a un WorkManager para su ejecución bajo el contexto de hebra de la hebra de creación. Si la intención es ejecutar en la hebra de invocación (el 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"));
// Puede invocar 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);
// 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 para una tarea, que se puede enviar posteriormente a un WorkManager para su ejecución bajo el contexto de hebra de la hebra de creación. Si la intención es ejecutar en una hebra agrupada (método startWork de WorkManager), se puede conseguir el 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 captura de contexto de hebra y propagación.

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);

Opciones adicionales para tareas contextuales para la ejecución diferida

Al enviar una tarea para la ejecución diferida, puede asignar opcionalmente un escucha y un tiempo de espera de inicio e indicar si se espera que la ejecución dure mucho tiempo. El tiempo de espera de inicio sólo está disponible como un parámetro en beans asíncronos, pero para CommonJ and 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 de coordinación entre aplicaciones y otros artefactos para supervisar la disponibilidad. Concurrency Utilities for Java EE no proporciona ningún equivalente. Si se requiere una sustitución para esta capacidad, puede hacerlo implementando una aplicación conocida a todas las demás aplicaciones que actúa como el equivalente de SubsystemMonitorManager.

Manejo de sucesos

Los beans asíncronos proporcionan la capacidad de registrar escuchas para diversos tipos de sucesos que se producen en AlarmManager, AsynchScope, EventSource, SubsystemMonitor, WorkManager y Work. La mayoría de los sucesos no tienen ningún equivalente directo en Concurrency Utilities for Java EE. La responsabilidad se deja a las aplicaciones para implementar sus propios mecanismos para sucesos y modificaciones. En un par de casos, Concurrency Utilities for Java EE proporciona una capacidad similar. En algunos casos, es posible que pueda utilizar ManagedTaskListener, que se registra de forma más granular (al enviar la tarea) en lugar de AlarmManagerEvents y WorkEvents.

Manejo de sucesos para una anomalía que se produce durante la invocación de un proxy contextual

En los beans asíncronos, cuando se utiliza un proxy contextul para invocar una operación y la operación emite una excepción declarada, la excepción no se notifica al invocador. En lugar de ello, la excepción se notifica en el suceso listenerExceptionThrown a los escuchas EventSourceEvents. En Concurrency Utilities for Java EE, el invocador puede detectar la excepción y gestionarla.

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;
}

Icon that indicates the type of topic Reference topic



Timestamp icon Last updated: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=rasb_migrate_to_eeconcurrency
File name: rasb_migrate_to_eeconcurrency.html