Beispiele für die Migration auf EE Concurrency von asynchronen Beans und CommonJ

Sie können Anwendungen, die asynchrone Beans und die CommonJ-APIs "Timer" und "Work Manager" verwenden, migrieren, sodass sie Concurrency Utilities for Java™ EE verwenden.

Concurrency Utilities for Java EE bietet einen standardisierten Ansatz für die parallele Ausführung von Operationen in einem Anwendungsserver. Dieses Feature ersetzt die Programmiermodelle für asynchrone Beans sowie für CommonJ Timer und Work Manager. Die Codebeispiele auf dieser Seite zeigen, wie vorhandene Anwendungen migriert werden, sodass sie Concurrency Utilities for Java EE verwenden.

Veraltetes Feature Veraltetes Feature: Asynchrone Beans und CommonJ-APIs sind veraltet. depfeat

In den Codebeispielen verwendete Ressourcen

In den Codebeispielen auf dieser Seite wird davon ausgegangen, dass die Anwendung die folgenden Ressourcen eingefügt oder gesucht hat:

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

Basistaskimplementierung

Dieser Abschnitt enthält Beispiele einfacher Taskimplementierungen, die in den anderen nachfolgenden Beispielen in diesem Dokument verwendet werden. Für asynchrone Beans ist eine eigene Schnittstelle, AlarmListener, für Tasks erforderlich, deren Ausführung für die Zukunft geplant ist. Für CommonJ ist eine eigene Schnittstelle, TimerListener, für Tasks erforderlich, deren Ausführung für die Zukunft geplant ist. Concurrency Utilities for Java EE-Tasks können Runnable oder Callable sein und für diese Tasks können beide Schnittstellen verwendet werden, unabhängig davon, ob eine Task für die sofortige Ausführung übergeben wird oder ihre Ausführung für die Zukunft geplant wird. In einigen Fällen kann Work für asynchrone Beans oder CommonJ an ein verwaltetes Steuerprogramm ohne Änderungen als Runnable übergeben werden. Die Work-Methode release wird durch die Funktion verwalteter Steuerprogramme ersetzt, aktive Threads abzubrechen und zu unterbrechen. Die Work-Methode isDaemon wird durch die Ausführungseigenschaft LONGRUNNING_HINT ersetzt.

Work-Beispieltask für asynchrone 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 asynchrone 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++;
        // Optional neu planen:
        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 asynchrone 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++;
        // Optional neu planen:
        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();
    }
}

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

Beispiel für eine Callable-Task 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 asynchrone Beans, die eine Basisdatenbankeinfügung vornimmt:

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 asynchrone Beans, die eine Basisdatenbankeinfügung vornimmt:

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 vornimmt:

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 vornimmt:

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 vornimmt:

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 zu übergeben, die in einem Pool-Thread ausgeführt werden soll, und das Ergebnis abzurufen.

Beispiel für asynchrone 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 zuweisen und angeben, ob eine lange Ausführung der Task erwartet wird. Das Startzeitlimit ist nur als Parameter in asynchronen Beans verfügbar. Für CommonJ und Concurrency Utilities for Java EE kann ein Startzeitlimit in WorkListener oder ManagedTaskListener implementiert werden.

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

Auf den Abschluss der Ausführung einer Gruppe von Tasks warten

Alle drei Programmiermodelle bieten Möglichkeiten, auf den Abschluss der Ausführung einer Gruppe von Tasks zu warten. Die folgenden Beispiele geben eine maximale Wartezeit an. Es kann auch für eine unbestimmte Zeit gewartet werden oder es kann Concurrency Utilities for Java EE verwendet werden, um für die future-Variablen nacheinander jeweils eine get-Methode aufzurufen.

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

Auf den Abschluss der Ausführung einer einzigen Task in einer Gruppe warten

Alle drei Programmiermodelle bieten Möglichkeiten, auf den Abschluss der Ausführung einer einzigen Tasks in einer Gruppe zu warten. Die folgenden Beispiele geben eine maximale Wartezeit an, es kann aber auch für eine unbestimmte Zeit gewartet werden.

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

Ursachenausnahme beim Fehlschlagen einer Task abrufen

Alle drei Programmiermodelle bieten Möglichkeiten, die Ursachenausnahme beim Fehlschlagen der Taskausführung abzurufen. Dies kann mit Listenern (Beispiele folgen auf dieser Seite) oder beim Abrufen der Taskergebnisse von WorkItem oder Future geschehen. WorkException oder ExecutionException wird mit der ursprünglichen Ausnahme als Ursache ausgegeben.

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

Einmalige Ausführung einer Task nach einem Intervall planen

Alle drei Programmiermodelle bieten eine Möglichkeit, die Ausführung einer Basistask in einem Pool-Thread zu einem Zeitpunkt in der Zukunft zu planen und das Ergebnis abzurufen.

Beispiel für asynchrone 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();
// Ergebnis abfragen
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();
// Ergebnis abfragen
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);

Wiederholte Ausführung einer Task in einem festen Intervall planen und Intervall bis zur nächsten Ausführung abfragen

CommonJ- und Concurrency Utilities for Java EE-Programmiermodelle bieten eine Möglichkeit, die wiederholte Ausführung einer Task in einem festen Intervall (z. B. stündlich zu Beginn der Stunde) zu planen. Die Echtzeitplanung wird nicht sichergestellt. Die Task kann zu einem beliebigen Zeitpunkt nach diesem Zeitpunkt gestartet werden, aber nicht früher. CommonJ- und Concurrency Utilities for Java EE-Programmiermodelle bieten außerdem eine Methode zur Vereinfachung, mit der die Verzögerung bis zur nächsten Ausführung berechnet werden kann.

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

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

CommonJ- und Concurrency Utilities for Java EE-Programmiermodelle bieten eine Möglichkeit, die wiederholte Ausführung einer Task in einem festen Intervall zwischen dem Ende einer Ausführung und dem Start der nächsten zu planen. Die Echtzeitplanung wird nicht sichergestellt. Die Task kann zu einem beliebigen Zeitpunkt nach diesem Zeitpunkt gestartet werden, aber nicht früher. Asynchrone Beans stellen eine Zurücksetzungsmethode für Alarm bereit, die verwendet werden kann, um dasselbe Verhalten zu erzielen. Alle drei Programmiermodelle bieten eine Möglichkeit, den Start weiterer Ausführungen einer geplanten Task zu verhindern.

Beispiel für asynchrone Beans:

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

Beispiel für CommonJ:

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

Beispiel für Concurrency Utilities for Java EE:

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

Wiederholte Ausführung einer Task in unterschiedlichen Intervallen planen

In allen drei Programmiermodellen kann bei jeder Ausführung das Intervall berechnet werden, nach dem die wiederholte Ausführung einer Task stattfindet. Asynchrone Beans stellen eine Zurücksetzungsmethode für Alarme bereit. Mit Concurrency Utilities for Java EE können Sie einen Trigger (Auslöser) einsetzen, der die nächste Ausführungszeit berechnet. CommonJ bietet diese Funktionen nicht, aber in CommonJ und anderen Programmiermodellen kann die Task nach Abschluss der vorherigen Ausführung neu geplant werden. In den folgenden Beispielen wird eine Task so geplant, dass sie genau viermal mit einer anderen Verzögerung vor jeder Ausführung ausgeführt wird. Der Code zum Zurücksetzen, erneuten Planen oder Berechnen der nächsten Ausführung befindet sich im Trigger in diesem Abschnitt und den AlarmListener- und TimerListener-Implementierungen, die Sie im Abschnitt Basistaskimplementierung finden.

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

TimerManager von CommonJ stellt Schnittstellen bereit, mit denen die Ausführung von Tasks ausgesetzt und fortgesetzt werden kann. Concurrency Utilities for Java EE stellt diesbezüglich eine differenziertere Funktion über die Methode skipRun des modular aufgebauten Triggermechanismus bereit. Eine einzige Triggerinstanz kann einer Reihe von Tasks bereitgestellt werden, vorausgesetzt die Triggerimplementierung bietet Unterstützung hierfür. Im folgenden Beispiel wird der Trigger für das Planen der Ausführung einer einzigen Task geschrieben.

Beispiel für CommonJ:

Timer timer = timerManager.schedule(
    new PrimeFinderTimerListener(100),
    new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(5)));
timerManager.suspend();
// ... zu einem späteren Zeitpunkt fortsetzen
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;
// ... zu einem späteren Zeitpunkt fortsetzen
if (trigger.isSuspended)
    trigger.isSuspended = false;

Weitere Ausführung von Tasks stoppen

Asynchrone Beans bieten eine Möglichkeit, AsynchScope zu löschen, wodurch alle von AlarmManagers in diesem Geltungsbereich erstellten Alarme abgebrochen werden. TimerManager von CommonJ bietet Schnittstellen, mit denen der Start weiterer Ausführungen verhindert und gewartet wird, bis alle aktiven Tasks gestoppt wurden. Dies ist möglich, weil bei jeder Suche von TimerManager eine neue Instanz generiert wird, die unabhängig von anderen Instanzen gestoppt werden kann. In Concurrency Utilities for Java EE wird derselbe ManagedScheduledExecutorService bei Suchen gemeinsam genutzt und Lebenszyklusoperationen wie shutdown, isTerminated und awaitTermination sind nicht zulässig (gemäß Spezifikation). Mit Concurrency Utilities for Java EE können Sie aber ein ähnliches Verhalten erzielen, indem Sie einem nicht verwalteten ScheduledExecutorService eine ManagedThreadFactory bereitstellen.

Beispiel für asynchrone Beans:

alarmManager.create(
    new PrimeFinderAlarmListener(100),
    null, 
    (int) TimeUnit.HOURS.toMillis(1));
alarmManager.create(
    new PrimeFinderAlarmListener(200),
    null, 
    (int) TimeUnit.HOURS.toMillis(2));
// ... Asynchronen Geltungsbereich löschen, um alle Alarme abzubrechen
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)));
// ... Zeitgebermanager stoppen
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);
// .. Steuerprogramm beenden
executor.shutdown();
if (!executor.isTerminated())
    executor.awaitTermination(TIMEOUT_MS, TimeUnit.MILLISECONDS);

Kontextabhängige Proxys erstellen

Mit Programmiermodellen von asynchronen Beans und Concurrency Utilities for Java EE können Sie kontextabhängige Proxys erstellen. Der Threadkontext wird aus dem Thread erfasst, der den kontextabhängien Proxy erstellt, in diesem gespeichert und automatisch auf den Ausführungsthread angewendet, wenn Schnittstellenmethoden für den Proxy aufgerufen und hinterher aus dem Ausführungsthread entfernt werden. Asynchrone Beans ermöglichen dies über EventSource. Concurrency Utilities for Java EE ermöglicht dies über ContextService.

Beispiel für asynchrone Beans:

EventSource eventSource = abWorkManager.createEventSource();
eventSource.addListener(new DBWriterImpl());
DBWriter dbWriter = (DBWriter) eventSource.getEventTrigger(DBWriter.class);
// Schnittstellenmethoden können über jeden Thread aufgerufen werden...
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);
// Schnittstellenmethoden können über jeden Thread aufgerufen werden...
int numUpdates = dbWriter.exec(
    "INSERT INTO AIRPORTS VALUES(?,?)", "AXN", "Alexandria Municipal Airport");

Kontextabhängige Proxys für mehrere Instanzen erstellen, die in der Transaktion des Ausführungsthreads ausgeführt werden

Asynchrone Beans und Concurrency Utilities for Java EE ermöglichen Ihnen anzugeben, ob Schnittstellenmethoden des kontextabhängigen Proxys in der Transaktion des Ausführungsthreads ausgeführt werden oder ob die aktuelle Transaktion ausgesetzt wird und ein bereinigter Transaktionskontext während der Ausführung der Methode angewendet wird. Eine weitere Funktion asynchroner Beans ist, dass mehrere Listenerinstanzen mit einem einzigen Proxy ausgelöst werden können. Concurrency Utilities for Java EE bietet diese Funktion aber nicht und analoges Verhalten kann durch Schreiben eines Wrapper-Listeners erzielt werden, der die Aufgaben an viele andere delegiert. Im folgenden Beispiel wird ein einziger Proxy aufgerufen, der mehrere Listenerinstanzen unter der Transaktion des aufrufenden Threads auslöst.

Beispiel für asynchrone 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);
// Schnittstellenmethoden können über jeden Thread aufgerufen werden...
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);
// Schnittstellenmethoden können über jeden Thread aufgerufen werden...
tran.begin();
try  {    
    eventTrigger.call();
} finally {
    tran.commit();
}

Kontextabhängige Tasks für die verzögerte Ausführung im aufrufenden Thread erstellen

Mit asynchronen Beans können Sie WorkWithExecutionContext erstellen. Dies ist im Grunde ein serialisierbarer kontextabhängiger Proxy für eine Task, die zu einem späteren Zeitpunkt an einen WorkManager für die Ausführung im Threadkontext des erstellenden Threads übergeben werden kann. Wenn die Ausführung im aufrunfenden Thread (doWork-Methode von WorkManager) beabsichtigt ist, kann ein kontextabhängiger Proxy analoges Verhalten in Concurrency Utilities for Java EE erzielen.

Beispiel für asynchrone Beans:

WorkWithExecutionContext contextualWork = abWorkManager.create(
    new DBInsertWorkAB("BJI", "Bemidji Regional Airport"));
// kontextabhängige Arbeit kann in jedem Thread ausgeführt werden...
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);
// kontextabhängiger Proxy kann in jedem Thread ausgeführt werden...
int numUpdates = contextualTask.call();

Kontextabhängige Tasks für die verzögerte Ausführung in einem Pool-Thread erstellen

Mit asynchronen Beans können Sie WorkWithExecutionContext erstellen. Dies ist im Grunde ein serialisierbarer kontextabhängiger Proxy für eine Task, die zu einem späteren Zeitpunkt an einen WorkManager für die Ausführung im Threadkontext des erstellenden Threads übergeben werden kann. Wenn die Ausführung im Pool-Thread (startWork-Methode von WorkManager) beabsichtigt ist, kann analoges Verhalten in Concurrency Utilities for Java EE erzielt werden, indem ein kontextabhängiger Proxy für eine Task an ein verwaltetes Steuerprogramm übergeben wird. Dies bietet aber eine geringere Effizienz, weil der Threadkontext doppelt erfasst und weitergegeben wird.

Beispiel für asynchrone 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 kontextabhängige Tasks 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 zuweisen und angeben, ob eine lange Ausführung der Task erwartet wird. Das Startzeitlimit ist nur als Parameter in asynchronen Beans verfügbar. Für CommonJ und Concurrency Utilities for Java EE kann ein Startzeitlimit in WorkListener oder ManagedTaskListener implementiert werden.

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

Asynchrone Beans stellen SubsystemMonitor und SubsystemMonitorManager als Mechanismus für die Koordination in mehreren Anwendungen oder anderen Artefakten für die Überwachung der Verfügbarkeit bereit. Concurrency Utilities for Java EE stellt keine entsprechende Funktion bereit. Wenn 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 fungiert.

Behandlung von Ereignissen

Asynchrone Beans stellen die Funktion bereit, Listener für verschiedene Typen von Ereignissen zu registrieren, die in AlarmManager, AsynchScope, EventSource, SubsystemMonitor, WorkManager und Work auftreten. Die meisten dieser Ereignisse haben keine direkte Entsprechung in Concurrency Utilities for Java EE. Den Anwendungen wird die Zuständigkeit überlassen, eigene Mechanismen für Ereignisse und Benachrichtigungen zu implementieren. In einigen Fällen stellt Concurrency Utilities for Java EE eine ähnliche Funktion bereit. Sie können in einigen Fällen möglicherweise ManagedTaskListener, der (bei der Übergabe der Task) differenzierter registriert wird, anstelle von AlarmManagerEvents und WorkEvents verwenden.

Behandlung von Ereignissen bei Fehlern, die beim Aufruf eines kontextabhängigen Proxys auftreten

Wenn in asynchronen Beans ein kontextabhängiger Proxy zum Aufrufen einer Operation verwendet wird und die Operation eine deklarierte Ausnahme auslöst, wird die Ausnahme dem Aufrufer nicht zurückgemeldet. Stattdessen wird die Ausnahme im Ereignis "listenerExceptionThrown" an EventSourceEvents-Listener gemeldet. In Concurrency Utilities for Java EE kann der Aufrufer die Ausnahme abfagen und bearbeiten.

Beispiel für asynchrone 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);
// Schnittstellenmethoden können über jeden Thread aufgerufen werden...
try  {    
    dbWriter.exec(
        "INSERT INTO AIRPORTS VALUES(?,?)", "KAUM", "Austin Municipal Airport");
} catch (Exception x) {
    // Fehlschlagen wird erwartet
}
Throwable exception = listenerException.get();

Beispiel für Concurrency Utilities for Java EE:

DBWriter dbWriter = contextService.createContextualProxy(
    new DBWriterImpl(), DBWriter.class);
// Schnittstellenmethoden können über jeden Thread aufgerufen werden...
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: 25.05.2016
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=rasb_migrate_to_eeconcurrency
Dateiname:rasb_migrate_to_eeconcurrency.html