Exemplos para migrar a Simultaneidade EE de Beans assíncronos e CommonJ

É possível migrar aplicativos que usam Beans assíncronos e APIs CommonJ Timer e Work Manager para usar o Concurrency Utilities for Java™ EE.

Recursos usados nos exemplos de código

Os exemplos de código nessa página consideram que o aplicativo injetou ou consultou os seguintes recursos:

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

Implementação de tarefa básica

Esta seção fornece alguns exemplos de implementações de tarefas simples que são usados pelos outros exemplos em todo o restante deste documento. Os beans assíncronos requerem uma interface separada, AlarmListener, para tarefas que estão planejadas para execução no futuro. CommonJ requer uma interface separada, TimerListener, para tarefas que estão planejadas para execução no futuro. As tarefas do Concurrency Utilities for Java EE podem ser Runnable ou Callable e permitem que qualquer interface seja usada, independentemente se uma tarefa é enviada para execução imediatamente ou planejada para execução no futuro. Em alguns casos, é possível enviar Beans assíncronos ou Trabalho CommonJ como Runnable para um executor gerenciado sem mudanças. O método de Trabalho release é substituído pela capacidade de executores gerenciados de cancelarem e interromperem encadeamentos em execução. O método de Trabalho isDaemon é substituído pela propriedade de execução LONGRUNNING_HINT.

Tarefa Work de exemplo para Beans assíncronos e CommonJ que localiza o próximo 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();
    }
}

Tarefa AlarmListener de exemplo para Beans assíncronos que localiza o próximo 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();
    }

Tarefa TimerListener de exemplo para Beans assíncronos que localiza o próximo 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();
    }
}

Exemplo de uma tarefa Runnable para o Concurrency Utilities for Java EE que localiza o próximo 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();
    }
}

Exemplo de uma tarefa Callable para o Concurrency Utilities for Java EE que localiza o próximo 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++;
    }
}

Tarefa Work de exemplo para Beans assíncronos que executam uma inserção de banco de dados básico:

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

Tarefa AlarmListener de exemplo para beans assíncronos que executam uma inserção de banco de dados básico:

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

Tarefa Work de exemplo para CommonJ que executa uma inserção de banco de dados básico:

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

Tarefa TimerListener de exemplo para CommonJ que executa uma inserção de banco de dados básico:

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

Tarefa Callable de exemplo para Concurrency Utilities for Java EE que executa uma inserção de banco de dados básico:

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

Enviando uma tarefa

Todos os três modelos de programação fornecem uma maneira de enviar uma tarefa básica para execução em um encadeamento agrupado e obter o resultado.

Exemplo de beans assí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();
}

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

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

Mais opções ao enviar uma tarefa

Ao enviar uma tarefa, opcionalmente, é possível designar um tempo limite de listener e de início e indicar se é esperado que ela seja executada por um longo tempo. O tempo limite de início está disponível apenas como um parâmetro em Beans assíncronos, mas para CommonJ e Concurrency Utilities for Java EE, um tempo limite de início pode ser implementado no WorkListener ou ManagedTaskListener.

Exemplo de beans assí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();
}

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

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

Esperando a conclusão de um grupo de tarefas

Todos os três modelos de programação fornecem maneiras de esperar a conclusão de um grupo de tarefas. Os exemplos a seguir especificam uma quantidade máxima de tempo de espera. É possível esperar indefinidamente ou usar o Concurrency Utilities for Java EE para executar get sequencialmente nas variáveis 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();
}

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

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

Esperando a conclusão de uma única tarefa em um grupo

Todos os três modelos de programação fornecem maneiras de esperar a conclusão de uma única tarefa em um grupo. Os exemplos a seguir especificam uma quantidade máxima de tempo de espera, mas também é possível esperar indefinidamente.

Exemplo de beans assí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();
}

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

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

Obtendo a exceção de causa quando uma tarefa falha

Todos os três modelos de programação fornecem maneiras de obter a exceção de causa quando a execução da tarefa falha. Isso pode ser feito com os listeners (exemplos podem ser encontrados posteriormente nesta página) ou ao obter o resultado da tarefa, de WorkItem ou de Future. É gerado WorkException ou ExecutionException, contendo a exceção original como a causa.

Exemplo de beans assí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();
    }

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

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

Planejando uma tarefa única para execução após um intervalo

Todos os três modelos de programação fornecem uma maneira de planejar uma tarefa básica para execução em um encadeamento agrupado em algum ponto no futuro e obter o resultado.

Exemplo de beans assí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();

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

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

Planejando uma tarefa de repetição em uma taxa fixa e consultando o intervalo até a próxima execução

Os modelos de programação CommonJ e Concurrency Utilities for Java EE fornecem uma maneira de planejar uma tarefa de repetição para execução em uma taxa fixa (por exemplo, a cada hora no início da hora). O planejamento em tempo real não é garantido. A tarefa pode iniciar em qualquer ponto após este tempo, mas não mais cedo. Os modelos de programação CommonJ e Concurrency Utilities for Java EE também fornecem um método de conveniência para calcular o atraso até a próxima execução.

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

Exemplo de Concurrency Utilities for Java EE:

ScheduledFuture<?> future = executor.scheduleAtFixedRate(
    new PrimeFinderRunnable(120), 90, 30, TimeUnit.MINUTES);
long delay = future.getDelay(TimeUnit.SECONDS);

Planejando uma tarefa de repetição com um atraso fixo entre as execuções e cancelando a tarefa

Os modelos de programação CommonJ e Concurrency Utilities for Java EE fornecem uma maneira de planejar uma tarefa de repetição para execução com um intervalo fixo entre o término de uma execução e o início da próxima. O planejamento em tempo real não é garantido. A tarefa pode iniciar em qualquer ponto após este tempo, mas não mais cedo. Os beans assíncronos fornecem um método de reconfiguração em Alarm que pode ser usado para obter esse mesmo comportamento. Todos os três modelos de programação fornecem uma maneira de cancelar o início de execuções adicionais de uma tarefa planejada.

Exemplo de beans assí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();

Exemplo de CommonJ:

Timer timer = timerManager.schedule(
    new PrimeFinderTimerListener(90), 50, 50);
// ... eventually cancel the timer
timer.cancel();

Exemplo de Concurrency Utilities for Java EE:

ScheduledFuture<?> future = executor.scheduleWithFixedDelay(
    new PrimeFinderRunnable(90), 50, 50, TimeUnit.MILLISECONDS);
// ... eventually cancel the task
future.cancel(false);

Planejando uma tarefa de repetição para execução em intervalos variados

É possível em todos os três modelos de programação calcular com cada execução o intervalo após o qual a próxima tarefa de repetição se repetirá. Os beans assíncronos fornecem um método de reconfiguração para alarmes. O Concurrency Utilities for Java EE permite conectar um Acionador que calcula o próximo tempo de execução. O CommonJ não fornece nenhum desses, mas é possível em CommonJ e em outros modelos de programação replanejar a tarefa conforme a execução anterior é concluída. Nos exemplos a seguir, uma tarefa é planejada para execução exatamente quatro vezes, com um atraso diferente antes de cada execução. O código para reconfigurar, replanejar ou calcular a próxima execução está localizado no Acionador incluído nessa seção e nas implementações AlarmListener e TimerListener, que estão incluídas na seção Implementação de tarefa básica.

Exemplo de beans assí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();

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

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

Suspendendo e continuando a execução de tarefas

O CommonJ TimerManager fornece interfaces para suspender e continuar a execução de tarefas. O Concurrency Utilities for Java EE fornece essa capacidade em uma base mais granular através do método skipRun do mecanismo do Acionador que pode ser conectado. Uma única instância do Acionador pode ser fornecida para qualquer número de tarefas, desde que o Acionador seja implementado para suportar isso. No exemplo a seguir, o Acionador é gravado para ser usado para o planejamento de uma única tarefa.

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

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

Parando a execução adicional de tarefas

Os beans assíncronos fornecem uma maneira de destruir o AsynchScope, que cancela todos os alarmes criados pelos AlarmManagers nesse escopo. O CommonJ TimerManager fornece interfaces para parar o início de execuções adicionais e esperar a parada de todas as tarefas em execução. Isso é possível porque cada consulta de um TimerManager produz uma nova instância, que pode parar independentemente de outras. No Concurrency Utilities for Java EE, o mesmo ManagedScheduledExecutorService é compartilhado entre consultas e operações de ciclo de vida, como shutdown, isTerminated e awaitTermination não são permitidas (por segundo). No entanto, com o Concurrency Utilities for Java EE, é possível obter um comportamento semelhante, fornecendo um ManagedThreadFactory para um ScheduledExecutorService não gerenciado.

Exemplo de beans assí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();

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

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

Construindo proxies contextuais

Os modelos de programação Beans assíncronos e Concurrency Utilities for Java EE permitem construir proxies contextuais. O contexto de encadeamento é capturado do encadeamento que cria o proxy contextual e está armazenado nele, sendo aplicado automaticamente ao encadeamento de execução quando os métodos de interface são chamados no proxy e sendo removido do encadeamento de execução posteriormente. Os beans assíncronos fornecem isso por meio do EventSource. O Concurrency Utilities for Java EE fornece isso por meio do ContextService.

Exemplo de beans assíncronos:

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

Exemplo de 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");

Construindo proxies contextuais para várias instâncias em execução na transação do encadeamento de execução

Os beans assíncronos e o Concurrency Utilities for Java EE permitem especificar se os métodos de interface do proxy de contexto são executados na transação do encadeamento de execução, ou se a transação atual é suspensa e um contexto de transação limpo é aplicado durante o método. Outra capacidade de Beans assíncronos é que eles permitem que várias instâncias de listener sejam acionadas por um único proxy. No entanto, o Concurrency Utilities for Java EE não possui essa capacidade e um comportamento análogo pode ser obtido gravando um listener de wrapper que delega a vários outros. O exemplo a seguir chama um único proxy que aciona várias instâncias de listener, tudo isso sob a transação do encadeamento de chamada.

Exemplo de beans assí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);
// Can invoke interface methods from any thread...
tran.begin();
try {
    eventTrigger.call();
} finally {
    tran.commit();
}

Exemplo 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);
// Can invoke interface methods from any thread...
tran.begin();
try {
    eventTrigger.call();
} finally {
    tran.commit();
}

Criando tarefas contextuais para execução adiada no encadeamento de chamada

Os beans assíncronos permitem criar WorkWithExecutionContext, que é basicamente um proxy contextual serializável para uma tarefa, que pode ser enviado posteriormente para um WorkManager para execução sob o contexto de encadeamento do encadeamento de criação. Se a intenção é executar no encadeamento de chamada (método doWork do WorkManager), um proxy contextual pode realizar o comportamento análogo no Concurrency Utilities for Java EE.

Exemplo de beans assíncronos:

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

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

Criando tarefas contextuais para execução adiada em um encadeamento agrupado

Os beans assíncronos permitem criar WorkWithExecutionContext, que é basicamente um proxy contextual serializável para uma tarefa, que pode ser enviado posteriormente para um WorkManager para execução sob o contexto de encadeamento do encadeamento de criação. Se a intenção é executar em um encadeamento agrupado (método startWork do WorkManager), o comportamento análogo pode ser realizado no Concurrency Utilities for Java EE, enviando um proxy contextual para uma tarefa a um executor gerenciado, que é menos eficiente devido à duplicação de captura e propagação do contexto de encadeamento.

Exemplo de beans assí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();
}

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

Opções adicionais para tarefas contextuais para execução adiada

Ao enviar uma tarefa para execução adiada, opcionalmente, é possível designar um tempo limite de listener e de início e indicar se é esperado que ela seja executada por um longo tempo. O tempo limite de início está disponível apenas como um parâmetro em Beans assíncronos, mas para CommonJ e Concurrency Utilities for Java EE, um tempo limite de início pode ser implementado no WorkListener ou ManagedTaskListener.

Exemplo de beans assí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();
}

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

Monitoramento de subsistema

Os beans assíncronos fornecem o SubsystemMonitor e SubsystemMonitorManager como um mecanismo a ser coordenado entre aplicativos ou outros artefatos para monitorar a disponibilidade. O Concurrency Utilities for Java EE não fornece nenhum equivalente. Se for necessária uma substituição para essa capacidade, isso poderá ser feito implementando um aplicativo que seja conhecido de todos os outros aplicativos, que aja como o equivalente do SubsystemMonitorManager.

Manipulação de Eventos

Os beans assíncronos permitem registrar listeners para vários tipos de eventos que ocorrem em AlarmManager, AsynchScope, EventSource, SubsystemMonitor, WorkManager e Work. A maioria desses eventos não possui nenhum equivalente direto no Concurrency Utilities for Java EE. É de responsabilidade dos aplicativos implementar seus próprios mecanismos para eventos e notificações. Em alguns casos, o Concurrency Utilities for Java EE fornece uma capacidade semelhante. Em alguns casos, é possível usar ManagedTaskListener, que é registrado em uma base mais granular (durante o envio da tarefa) no lugar de AlarmManagerEvents e WorkEvents.

Manipulação de eventos para falha que ocorre durante a chamada de um proxy contextual

Em Beans assíncronos, quando um proxy contextual é usado para chamar uma operação e a operação gera uma exceção declarada, a exceção não é relatada de volta ao invocador. Em vez disso, a exceção é relatada no evento listenerExceptionThrown para listeners EventSourceEvents. No Concurrency Utilities for Java EE, o invocador pode capturar a exceção e manipulá-la.

Exemplo de beans assí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);
// 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();

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

Ícone que indica o tipo de tópico Tópico de Referência



Ícone de registro de data e hora Última atualização: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=rasb_migrate_to_eeconcurrency
Nome do arquivo: rasb_migrate_to_eeconcurrency.html