Beispiel-API-Tasks, die Concurrency Utilities for Java EE implementieren

Sie können Anwendungen, die Asynchronous Beans-, CommonJ-Zeitgeber- und Arbeitsmanager-APIs verwenden, auf die Verwendung von Concurrency Utilities for Java™ EE migrieren.

In den Codebeispielen verwendete Ressourcen

Die Codebeispiele auf dieser Seite gehen davon aus, dass die folgenden Ressourcen von der Anwendung eingefügt bzw. gesucht wurden:

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

Implementierung von Basistasks

Dieser Abschnitt enthält verschiedene Beispiele für einfache Taskimplementierungen, die von den anderen Beispielen in diesem Dokument verwendet werden. Asynchronous Beans erfordert die gesonderte Schnittstelle AlarmListener für Tasks, deren künftige Ausführung geplant ist. CommonJ erfordert die gesonderte Schnittstelle TimerListener für Tasks, deren künftige Ausführung geplant ist. Concurrency Utilities for Java EE-Tasks können Runnable (Ausführbar) oder Callable (Ausführbar) sein und lassen die Verwendung beider Schnittstellen zu, unabhängig davon, ob eine Task zur sofortigen oder künftigen Ausführung übergeben wird. In manchen Fällen können Asynchronous Beans und CommonJ Work unverändert als Runnable an ein Steuerprogramm für verwaltete Tasks übergeben werden. Die Methode release von Work wurde durch die Fähigkeit der Steuerprogramme für verwaltete Tasks, aktive Threads abzubrechen und zu unterbrechen, ersetzt. Die Methode isDaemon von Work wurde durch die Ausführungseigenschaft LONGRUNNING_HINT ersetzt.

Work-Beispieltask für Asynchronous Beans und CommonJ, die die nächste Primzahl ermittelt:

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

AlarmListener-Beispieltask für Asynchronous Beans, die die nächste Primzahl ermittelt:

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

TimerListener-Beispieltask für Asynchronous Beans, die die nächste Primzahl ermittelt:

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

Runnable-Beispieltask für Concurrency Utilities for Java EE, die die nächste Primzahl ermittelt:

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

Callable-Beispieltask für Concurrency Utilities for Java EE, die die nächste Primzahl ermittelt:

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

Work-Beispieltask für Asynchronous Beans, die eine Basisdatenbankeinfügung durchführt:

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

AlarmListener-Beispieltask für Asynchronous Beans, die eine Basisdatenbankeinfügung durchführt:

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

Work-Beispieltask für CommonJ, die eine Basisdatenbankeinfügung durchführt:

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

TimerListener-Beispieltask für CommonJ, die eine Basisdatenbankeinfügung durchführt:

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

Callable-Beispieltask für Concurrency Utilities for Java EE, die eine Basisdatenbankeinfügung durchführt:

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

Task übergeben

Alle drei Programmiermodelle bieten eine Möglichkeit, eine Basistask zur Ausführung einem Pool-Thead zu übergeben und das Ergebnis abzurufen.

Beispiel für Asynchronous Beans:

WorkItem workItem = abWorkManager.startWork(
    new DBInsertWorkAB("DLH", "Duluth International Airport"));
ArrayList<WorkItem> items = new ArrayList<WorkItem>(1);
items.add(workItem);
if (abWorkManager.join(items, WorkManager.JOIN_AND, TIMEOUT_MS)) {
    DBInsertWorkAB work = (DBInsertWorkAB) workItem.getResult();
    int numUpdates = work.getResult();
}

Beispiel für 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();
}

Beispiel für Concurrency Utilities for Java EE:

Future<Integer> future = executor.submit(
    new DBInsertTask("INL", "Falls International Airport"));
int numUpdates = future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);

Weitere Optionen beim Übergeben einer Task

Beim Übergeben einer Task können Sie optional einen Listener und ein Startzeitlimit zuordnen und angeben, ob eine Langzeitausführung der Task erwartet wird. Das Startzeitlimit ist nur als Parameter in Asynchronous Beans verfügbar, aber für CommonJ und Concurrency Utilities for Java EE kann ein Startzeitlimit in WorkListener oder ManagedTaskListener implementiert werden.

Beispiel für Asynchronous Beans:

long startTimeout = TIMEOUT_MS;
boolean isLongRunning = true;
WorkItem workItem = abWorkManager.startWork(
    new DBInsertWorkAB("SGS", "South Saint Paul Municipal Airport"),
    startTimeout,
    new WorkListenerAB(),
    isLongRunning);
ArrayList<WorkItem> items = new ArrayList<WorkItem>(1);
items.add(workItem);
if (abWorkManager.join(items, WorkManager.JOIN_AND, Integer.MAX_VALUE)) {
    DBInsertWorkAB work = (DBInsertWorkAB) workItem.getResult();
    int numUpdates = work.getResult();
}

Beispiel für 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();
}

Beispiel für 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();

Abschluss einer Gruppe von Tasks abwarten

Alle drei Programmiermodelle bieten Möglichkeiten, auf den Abschluss einer Gruppe von Tasks zu warten. In den folgenden Beispielen wird eine maximale Wartezeit angegeben, da es möglich ist, unbegrenzt zu warten oder in Concurrency Utilities for Java EE sogar noch mehr Granularität hinzuzufügen, indem die Operation "get" nacheinander für die verschiedenen "Futures" aufgerufen wird.

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

Beispiel für 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();
}

Beispiel für 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();

Abschluss einer einzelnen Task in einer Gruppe abwarten

Alle drei Programmiermodelle bieten Möglichkeiten, auf den Abschluss einer einzelnen Task in einer Gruppe zu warten. In den folgenden Beispielen wird eine maximale Wartezeit angegeben, aber es auch möglich, unbegrenzt zu warten.

Beispiel für Asynchronous Beans:

ArrayList<WorkItem> items = new ArrayList<WorkItem>(3);
items.add(abWorkManager.startWork(new PrimeFinderWork(20)));
items.add(abWorkManager.startWork(new PrimeFinderWork(50)));
items.add(abWorkManager.startWork(new PrimeFinderWork(80)));
boolean anyCompleted = abWorkManager.join(items, WorkManager.JOIN_OR, TIMEOUT_MS);
long prime = -1;
for (WorkItem workItem : items) {
    if (workItem.getStatus() == WorkEvent.WORK_COMPLETED) {
        PrimeFinderWork work = (PrimeFinderWork) workItem.getResult();
        prime = work.getPrimeNumber();
    } else
        ((Work) workItem.getEventTrigger(Work.class)).release();
}

Beispiel für 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();
}

Beispiel für 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);

Ursächliche Ausnahme beim Fehlschlagen einer Task abrufen

Alle drei Programmiermodelle bieten Möglichkeiten, die ursächliche Ausnahme für das Fehlschlagen einer Taskausführung abzurufen. Sie können dazu Listener verwenden (Beispiele hierfür finden Sie weiter hinten auf dieser Seite) oder die Ursache beim Abrufen des Taskergebnisses von WorkItem oder Future anfordern. Es wird eine Ausnahme des Typs WorkException oder ExecutionException ausgelöst, die die ursprüngliche Ausnahme als Ursache enthält.

Beispiel für Asynchronous Beans:

boolean isLongRunning = false;
WorkItem workItem = abWorkManager.startWork(
    new DBInsertWorkAB("KADC", "Wadena Municipal Airport"),
    isLongRunning);
Throwable exception = null;
ArrayList<WorkItem> items = new ArrayList<WorkItem>(1);
items.add(workItem);
if (abWorkManager.join(items, WorkManager.JOIN_AND, TIMEOUT_MS))
    try  {
        DBInsertWorkAB work = (DBInsertWorkAB) workItem.getResult();
        int numUpdates = work.getResult();
    } catch (WorkException x) {
        exception = x.getCause();
    }

Beispiel für 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();
    }

Beispiel für 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();
}

Ausführung einer einmaligen Task nach einem Intervall planen

Alle drei Programmiermodelle bieten eine Möglichkeit, eine Basistask zur künftigen Ausführung in einem Pool-Thead zu planen und das Ergebnis abzurufen.

Beispiel für Asynchronous Beans:

AsynchScope asynchScope = abWorkManager.findOrCreateAsynchScope("MyScope");
AlarmManager alarmManager = asynchScope.getAlarmManager();
Alarm alarm = alarmManager.create(
    new DBInsertAlarmListener(),
    new String[] { "MSP", "Minneapolis-Saint Paul International Airport"},
    (int) TimeUnit.SECONDS.toMillis(1));
DBInsertAlarmListener alarmListener = (DBInsertAlarmListener) alarm.getAlarmListener();
// Poll for result to appear
for (long start = System.nanoTime();
    alarmListener.getResult() < 0 && System.nanoTime() - start < TIMEOUT_NS;
    Thread.sleep(200)) ;
int numUpdates = alarmListener.getResult();

Beispiel für 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();

Beispiel für 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);

Ausführung einer Wiederholungstasks in einem festgelegten Intervall planen und Zeitraum bis zur nächsten Ausführung abfragen

Die Programmiermodelle von CommonJ und Concurrency Utilities for Java EE bieten eine Möglichkeit, die Ausführung einer Wiederholungstask in einem festgelegten Intervall zu planen (z. B. stündlich, jeweils zu Beginn der Stunde). Eine Echtzeitplanung ist nicht gewährleistet. Die Task kann jederzeit nach der festgelegten Zeit, aber nicht früher gestartet werden. die Programmiermodelle von CommonJ und Concurrency Utilities for Java EE stellen auch eine Methode für die vereinfachte Ermittlung der Verzögerung bis zur nächsten Ausführung bereit.

Beispiel für 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());

Beispiel für Concurrency Utilities for Java EE:

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

Ausführung einer Wiederholungstask mit einer festen Verzögerung zwischen den Ausführungen planen und die Task abbrechen

Die Programmiermodelle von CommonJ und Concurrency Utilities for Java EE bieten eine Möglichkeit, die Ausführung einer Wiederholungstask in einem festgelegten Intervall zwischen dem Ende einer Ausführung und dem Anfang der nächsten zu planen. Eine Echtzeitplanung ist nicht gewährleistet. Die Task kann jederzeit nach der festgelegten Zeit, aber nicht früher gestartet werden. Asynchronous Beans stellt eine Rücksetzmethode in Alarm bereit, mit der dasselbe Verhalten erreicht werden kann. Alle drei Programmiermodelle bieten eine Möglichkeit, den Start weiterer Ausführungen einer geplanten Task abzubrechen.

Beispiel für Asynchronous Beans:

AsynchScope asynchScope = abWorkManager.findOrCreateAsynchScope("MyScope");
AlarmManager alarmManager = asynchScope.getAlarmManager();
Alarm alarm = alarmManager.create(
    new PrimeFinderAlarmListener(90), 50, 10);
// ... eventually cancel the alarm
alarm.cancel();

Beispiel für CommonJ:

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

Beispiel für Concurrency Utilities for Java EE:

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

Ausführung einer Wiederholungstask in variierenden Intervallen planen

In allen drei Programmiermodellen ist es möglich, bei jeder Ausführung den Zeitraum zu berechnen, nach dem eine Wiederholungstask als Nächstes wiederholt wird. Asynchronous Beans stellt eine Rücksetzmethode für Alarme bereit. Concurrency Utilities for Java EE ermöglicht Ihnen, einen Auslöser (Trigger) einzufügen, der die nächste Ausführungszeit berechnet. CommonJ stellt keine dieser Methoden bereit, aber in CommonJ und anderen Programmiermodellen kann die Task nach Abschluss der vorherigen Ausführung neu geplant werden. In den folgenden Beispielen wird die viermalige Ausführung einer Task mit einer jeweils anderen Verzögerung vor jeder Ausführung geplant. Der Code zum Zurücksetzen, Neuplanen und Berechnen der nächsten Ausführung ist in dem in diesem Abschnitt beschriebenen Auslöser und in den AlarmListener- und TimerListener-Implementierungen, die unter Implementierung von Basistasks beschrieben sind, enthalten.

Beispiel für Asynchronous Beans:

int initialDelay = 50;
int[] subsequentDelays = new int[] { 40, 80, 70 };
AsynchScope asynchScope = abWorkManager.findOrCreateAsynchScope("MyScope");
AlarmManager alarmManager = asynchScope.getAlarmManager();
Alarm alarm = alarmManager.create(
    new PrimeFinderAlarmListener(60),
    subsequentDelays,
    initialDelay);
Thread.sleep(5000);
PrimeFinderAlarmListener alarmListener =
    (PrimeFinderAlarmListener) alarm.getAlarmListener();
long prime = alarmListener.getPrimeNumber();

Beispiel für 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();

Beispiel für 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;
    }
}

Ausführung von Tasks aussetzen und fortsetzen

CommonJ TimerManager stellt Schnittstellen für das Aussetzen und Fortsetzen der Ausführung von Tasks bereit. Concurrency Utilities for Java EE bietet diese Funktionalität auf einer sogar noch differenzierten Basis - mit der Methode skipRun des Plug-in-Auslösermechanismus. Eine einzige Auslöserinstanz kann für eine beliebige Anzahl von Tasks bereitgestellt werden kann, sofern der Auslöser entsprechend implementiert ist. Im folgenden Beispiel ist der Auslöser für die Planung einer einzigen Task programmiert.

Beispiel für 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();

Beispiel für 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;

Weitere Ausführung von Tasks stoppen

Asynchronous Beans bietet eine Möglichkeit, den AsynchScope zu löschen, woraufhin alle von AlarmManager-Instanzen in diesem Geltungbereich (Scope) erstellten Alarme abgebrochen werden. CommonJ TimerManager stellt Schnittstellen bereit, mit denen der Start weiterer Ausführungen gestoppt und der Stopp aller aktiven Tasks abgewartet werden kann. Dies ist möglich, weil jede Suche eines TimerManager eine neue Instanz erzeugt, die unabhängig von anderen gestoppt werden kann. In Concurrency Utilities for Java EE wird derselbe ManagedScheduledExecutorService von allen Suchen gemeinsam genutzt und Lebenszyklusoperationen wie shutdown, isTerminated und awaitTermination sind gemäß Spezifikation nicht zulässig. Mit Concurrency Utilities for Java EE kann jedoch ein ähnliches Verhalten erreicht werden, indem eine ManagedThreadFactory an einen nicht verwalteten ScheduledExecutorService übergeben wird.

Beispiel für Asynchronous Beans:

alarmManager.create(
    new PrimeFinderAlarmListener(100),
    null,
    (int) TimeUnit.HOURS.toMillis(1));
alarmManager.create(
    new PrimeFinderAlarmListener(200),
    null,
    (int) TimeUnit.HOURS.toMillis(2));
// ... eventually destroy the asynch scope to cancel all alarms
asynchScope.destroy();

Beispiel für 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);

Beispiel für 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);

Kontextproxys erstellen

Die Programmiermodelle von Asynchronous Beans und Concurrency Utilities for Java EE ermöglichen Ihnen die Erstellung von Kontextproxys. Der Threadkontext wird von dem Thread erfasst, der den Kontextproxy erstellt, darin gespeichert und automatisch auf den Ausführungsthread angewendet, wenn Schnittstellenmethoden im Proxy aufgerufen werden, und anschließend aus dem Ausführungsthread entfernt. Asynchronous Beans bietet diese Funktionalität über EventSource. Concurrency Utilities for Java EE bietet diese Funktionalität über ContextService.

Beispiel für Asynchronous Beans:

EventSource eventSource = abWorkManager.createEventSource();
eventSource.addListener(new DBWriterImpl());
DBWriter dbWriter = (DBWriter) eventSource.getEventTrigger(DBWriter.class);
// Kann Schnittstellenmethoden in jedem Thread aufrufen...
int numUpdates = dbWriter.exec(
    "INSERT INTO AIRPORTS VALUES(?,?)", "AIT", "Aitkin Municipal Airport");

Beispiel für Concurrency Utilities for Java EE:

DBWriter dbWriter = contextService.createContextualProxy(
    new DBWriterImpl(), DBWriter.class);
// Kann Schnittstellenmethoden in jedem Thread aufrufen...
int numUpdates = dbWriter.exec(
    "INSERT INTO AIRPORTS VALUES(?,?)", "AXN", "Alexandria Municipal Airport");

Kontextproxys für mehrere Instanzen erstellen, die in der Transaktion des Ausführungsthreads ausgeführt werden

In Asynchronous Beans und Concurrency Utilities for Java EE können Sie angeben, ob Schnittstellenmethoden des Kontextproxys in der Transaktion des Ausführungsthreads ausgeführt werden oder ob die aktuelle Transaktion ausgesetzt und ein bereinigter Transaktionskontext während der Methode angewendet wird. Außerdem bietet Asynchronous Beans die Möglichkeit, dass mehrere Listenerinstanzen von einem einzigen Proxy ausgelöst werden. In Concurrency Utilities for Java EE gibt es diese Funktionalität jedoch nicht und ein ähnliches Verhalten kann nur durch Programmieren eines Wrapper-Listeners erreicht werden, der seine Arbeit an mehrere Instanzen delegiert. Im folgenden Beispiel wird ein einziger Proxy aufgerufen, der mehrere Listenerinstanzen auslöst, die alle in der Transaktion des aufrufenden Threads ausgeführt werden.

Beispiel für Asynchronous Beans:

boolean runInSameTran = true;
EventSource eventSource = abWorkManager.createEventSource();
eventSource.addListener(new DBInsertTask("MKT", "Mankato Regional Airport"));
eventSource.addListener(new DBInsertTask("ULM", "New Ulm Municipal Airport"));
eventSource.addListener(new DBInsertTask("OWA", "Owatonna Degner Regional Airport"));
Callable<?> eventTrigger = (Callable<?>) eventSource.getEventTrigger(
    Callable.class, runInSameTran);
// Kann Schnittstellenmethoden in jedem Thread aufrufen...
tran.begin();
try  {
    eventTrigger.call();
} finally {
    tran.commit();}

Beispiel für 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);
// Kann Schnittstellenmethoden in jedem Thread aufrufen...
tran.begin();
try  {
    eventTrigger.call();
} finally {
    tran.commit();}

Kontexttasks für die verzögerte Ausführung des aufrufenden Threads erstellen

Asynchronous Beans ermöglicht Ihnen die Erstellung eines WorkWithExecutionContext, bei dem es sich im Wesentlichen um einen serialisierbaren Kontextproxy für eine Task handelt, die später zur Ausführung im Threadkontext des erstellenden Threads an einen WorkManager übergeben werden kann. Wenn die Ausführung im aufrufenden Thread (Methode doWork von WorkManager) beabsichtigt ist, kann ein Kontextproxy ein analoges Verhalten in Concurrency Utilities for Java EE erreichen.

Beispiel für Asynchronous Beans:

WorkWithExecutionContext contextualWork = abWorkManager.create(
    new DBInsertWorkAB("BJI", "Bemidji Regional Airport"));
// Can run the contextual work on any thread...
abWorkManager.doWork(contextualWork);
DBInsertWorkAB work = (DBInsertWorkAB) contextualWork.getWork();
int numUpdates = work.getResult();

Beispiel für Concurrency Utilities for Java EE:

Callable<Integer> contextualTask = contextService.createContextualProxy(
    new DBInsertTask("BRD", "Brainerd Lakes Regional Airport"),
    Callable.class);
// Kann den Kontextproxy in jedem Thread ausführen...
int numUpdates = contextualTask.call();

Kontexttasks für die verzögerte Ausführung in einem Pool-Thread erstellen

Asynchronous Beans ermöglicht Ihnen die Erstellung eines WorkWithExecutionContext, bei dem es sich im Wesentlichen um einen serialisierbaren Kontextproxy für eine Task handelt, die später zur Ausführung im Threadkontext des erstellenden Threads an einen WorkManager übergeben werden kann. Wenn die Ausführung in einem Pool-Thread (Methode startWork von WorkManager) beabsichtigt ist, kann ein analoges Verhalten in Concurrency Utilities for Java EE durch Übergabe eines Kontextproxys für eine Task an ein verwaltetes Steuerprogramm erreicht werden, was wegen der Duplizierung der Erfassung und Weitergabe des Threadkontexts jedoch weniger effizient ist.

Beispiel für Asynchronous Beans:

WorkWithExecutionContext contextualWork = abWorkManager.create(
    new DBInsertWorkAB("ELO", "Ely Municipal Airport"));
WorkItem workItem = abWorkManager.startWork(contextualWork);
ArrayList<WorkItem> items = new ArrayList<WorkItem>(1);
items.add(workItem);
if (abWorkManager.join(items, WorkManager.JOIN_AND, TIMEOUT_MS)) {
    DBInsertWorkAB work = (DBInsertWorkAB) workItem.getResult();
    int numUpdates = work.getResult();
}

Beispiel für 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);

Weitere Optionen für Kontexttasks für die verzögerte Ausführung

Beim Übergeben einer Task für die verzögerte Ausführung können Sie optional einen Listener und ein Startzeitlimit zuordnen und angeben, ob eine Langzeitausführung der Task erwartet wird. Das Startzeitlimit ist nur als Parameter in Asynchronous Beans verfügbar, aber für CommonJ und Concurrency Utilities for Java EE kann ein Startzeitlimit in WorkListener oder ManagedTaskListener implementiert werden.

Beispiel für Asynchronous Beans:

long startTimeout = TIMEOUT_MS;
boolean isLongRunning = true;
WorkWithExecutionContext contextualWork = abWorkManager.create(
    new DBInsertWorkAB("FRM", "Fairmont Municipal Airport"));
WorkItem workItem = abWorkManager.startWork(
    contextualWork, startTimeout, new WorkListenerAB(), isLongRunning);
ArrayList<WorkItem> items = new ArrayList<WorkItem>(1);
items.add(workItem);
if (abWorkManager.join(items, WorkManager.JOIN_AND, Integer.MAX_VALUE)) {
    DBInsertWorkAB work = (DBInsertWorkAB) workItem.getResult();
    int numUpdates = work.getResult();
}

Beispiel für 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();

Subsystemüberwachung

Asynchronous Beans stellt SubsystemMonitor und SubsystemMonitorManager als Koordinationsmechanismus in Anwendungen und anderen Artefakte für die Überwachung der Verfügbarkeit bereit. Concurrency Utilities for Java EE stellt keine entsprechende Funktion bereit. Falls ein Ersatz für diese Funktion erforderlich ist, können Sie eine Anwendung implementieren, die allen anderen Anwendungen bekannt ist und als Äquivalent zu SubsystemMonitorManager agiert.

Ereignisverarbeitung

Asynchronous Beans bietet die Möglichkeit, Listener für verschiedene Typen von Ereignissen zu registrieren, die in AlarmManager, AsynchScope, EvenrtSource, SubsystemMonitor, WorkManager und Work eintreten. Die meisten dieser Ereignisse haben keine direkte Entsprechung in Concurrency Utilities for Java EE. Es bleibt den Anwendungen überlassen, eigene Mechanismen für Ereignisse und Benachrichtigungen zu implementieren. Ein einigen Fällen stellt Concurrency Utilities for Java EE eine ähnliche Funktion bereit. In manchen Fällen können Sie den ManagedTaskListener verwenden, der (bei der Übergabe der Task) anstelle von AlarmManagerEvents and WorkEvents auf differenzierterer Basis registriert wird.

Ereignisverarbeitung bei Fehlern, die während des Aufrufs eines Kontextproxys auftreten

Wenn in Asynchronous Beans ein Kontextproxy für den Aufruf einer Operation verwendet wird und die Operation eine deklarierte Ausnahme auslöst, wird die Ausnahme nicht zurück an den Aufrufer gemeldet. Stattdessen wird die Ausnahme im listenerExceptionThrown-Ereignis an die EventSourceEvents-Listener berichtet. In Concurrency Utilities for Java EE kann der Aufrufer die Ausnahme abfangen und behandeln.

Beispiel für Asynchronous Beans:

EventSource eventSource = abWorkManager.createEventSource();
eventSource.addListener(new DBWriterImpl());
eventSource.addListener(new EventSourceEvents() {
    public void listenerCountChanged(
        EventSource es, int oldCount, int newCount) {}

    public void listenerExceptionThrown(
        EventSource es, Object listener,
        String methodName, Throwable exception) {
        listenerException.set(exception);
    }

    public void unexpectedException(
        EventSource es, Object runnable, Throwable exception) {}
});
DBWriter dbWriter = (DBWriter) eventSource.getEventTrigger(DBWriter.class);
// Kann Schnittstellenmethoden in jedem Thread aufrufen...
try  {
    dbWriter.exec(
        "INSERT INTO AIRPORTS VALUES(?,?)", "KAUM", "Austin Municipal Airport");
} catch (Exception x) {
    // expecting this to fail
}
Throwable exception = listenerException.get();

Beispiel für Concurrency Utilities for Java EE:

DBWriter dbWriter = contextService.createContextualProxy(
    new DBWriterImpl(), DBWriter.class);
// Kann Schnittstellenmethoden in jedem Thread aufrufen...
SQLException exception = null;
try  {
    dbWriter.exec(
        "INSERT INTO AIRPORTS VALUES(?,?)", "KSBU", "Blue Earth Municipal Airport");
} catch (SQLException x) {
    exception = x;
}

Symbol das den Typ des Artikels anzeigt. Referenzartikel



Symbol für Zeitmarke Letzte Aktualisierung: 01.12.2016
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=rwlp_migrate_to_eeconcurrency
Dateiname: rwlp_migrate_to_eeconcurrency.html