Concurrency Utilities for Java EE를 구현하는 API 태스크 예
비동기 Bean 및 CommonJ 타이머 및 작업 관리자 API를 사용하는 애플리케이션을 Concurrency Utilities for Java™ EE를 사용하도록 마이그레이션할 수 있습니다.
Concurrency Utilities for Java EE는 애플리케이션 서버에서 동시 조작 수행을 위한 표준화된 접근 방식을 제공합니다. 이는 비동기 Bean 및 CommonJ 타이머 및 작업 관리자에 대한 프로그래밍 모델을 대체합니다.
- 코드 예에서 사용되는 자원
- 기본 태스크 구현
- 태스크 제출
- 태스크 그룹 완료 대기
- 그룹 내의 단일 태스크 완료 대기
- 태스크 실패 시 원인 예외 얻기
- 간격 이후에 실행되도록 1회용 태스크 스케줄
- 고정 비율로 태스크 반복 스케줄 및 다음 실행 시까지의 간격 조회
- 가변 간격으로 실행되도록 태스크 반복 스케줄
- 태스크 실행 일시중단 및 재개
- 태스크 추가 실행 중지
- 컨텍스트 프록시 구성
- 실행 스레드 트랜잭션에서 실행 중인 다중 인스턴스에 대한 컨텍스트 프록시 구성
- 스레드 호출 시에 지연 실행에 대한 컨텍스트 태스크 작성
- 지연 실행에 대한 컨텍스트 태스크의 추가 옵션
- 서브시스템 모니터링
- 이벤트 처리
- 컨텍스트 프록시의 호출 중에 발생하는 실패에 대한 이벤트 처리
코드 예에서 사용되는 자원
이 페이지의 코드 예는 다음 자원이 애플리케이션에 의해 삽입 또는 검색되었다고 가정합니다.
@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;
기본 태스크 구현
이 절에서는 이 문서의 나머지 부분에서 다른 예가 사용하는 단순 태스크 구현의 일부 예를 제공합니다. 비동기 Bean의 경우 나중에 실행되도록 스케줄된 태스크에 대해 별도의 인터페이스 AlarmListener가 필요합니다. CommonJ의 경우 나중에 실행되도록 스케줄된 태스크에 대해 별도의 인터페이스 TimerListener가 필요합니다. Concurrency Utilities for Java EE 태스크는 Runnable 또는 Callable이며 이 두 인터페이스 모두 태스크가 즉시 실행 또는 이후에 실행되도록 스케줄되었는지에 상관없이 모두 사용 가능합니다. 비동기 Bean 또는 CommonJ Work는 변경하지 않고도 관리 대상 실행기에 Runnable로 제출할 수 있는 경우도 있습니다. Work의 release 메소드는 실행 중인 스레드를 취소하거나 인터럽트하기 위해 관리 대상 실행기 기능으로 대체됩니다. Work의 isDaemon 메소드는 LONGRUNNING_HINT 실행 특성으로 대체됩니다.
다음 소수를 찾는 비동기 Bean 및 CommonJ 모두에 대한 Work 태스크 예:
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();
}
}
다음 소수를 찾는 비동기 Bean에 대한 AlarmListener 태스크 예:
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();
}
다음 소수를 찾는 비동기 Bean에 대한 TimerListener 태스크 예:
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();
}
}
다음 소수를 찾는 Concurrency Utilities for Java EE에 대한 Runnable 태스크 예:
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();
}
}
다음 소수를 찾는 Concurrency Utilities for Java EE에 대한 Callable 태스크 예:
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++;
}
}
기본 데이터베이스 삽입을 수행하는 비동기 Bean에 대한 Work 태스크 예:
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;
}
}
}
}
기본 데이터베이스 삽입을 수행하는 비동기 Bean에 대한 AlarmListener 태스크 예:
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);
}
}
}
기본 데이터베이스 삽입을 수행하는 CommonJ에 대한 Work 태스크 예:
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;
}
}
}
기본 데이터베이스 삽입을 수행하는 CommonJ에 대한 TimerListener 태스크 예:
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);
}
}
}
기본 데이터베이스 삽입을 수행하는 Concurrency Utilities for Java EE에 대한 Callable 태스크 예:
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();
}
}
}
태스크 제출
세 프로그래밍 모델 모두 풀링된 스레드에서 실행하고 결과를 얻기 위해 기본 태스크를 제출하는 방법을 제공합니다.
비동기 Bean 예:
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();
}
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();
}
Concurrency Utilities for Java EE 예:
Future<Integer> future = executor.submit(
new DBInsertTask("INL", "Falls International Airport"));
int numUpdates = future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
태스크 제출 시 추가 옵션
태스크를 제출할 때 선택적으로 리스너와 시작 제한시간을 지정하고 장기간 실행되는지 여부를 표시할 수 있습니다. 시작 제한시간은 비동기 Bean에서는 매개변수로만 사용할 수 있지만 CommonJ 및 Concurrency Utilities for Java EE에 대해 시작 제한시간은 WorkListener 또는 ManagedTaskListener 내에서 구현 가능합니다.
비동기 Bean 예:
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();
}
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();
}
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();
태스크 그룹 완료 대기
세 프로그래밍 모델 모두 태스크 그룹이 완료될 때까지 대기하는 방법을 제공합니다. 다음 예는 다양한 미래에 get을 순차적으로 호출하여 무한정 기다리거나 Concurrency Utilities for Java EE에서 훨씬 더 많은 세분성을 추가할 수 있기 때문에 대기할 최대 시간을 지정합니다.
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();
}
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();
}
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();
그룹 내의 단일 태스크 완료 대기
세 프로그래밍 모델 모두 그룹 내의 단일 태스크가 완료될 때까지 대기하는 방법을 제공합니다. 다음 예는 최대 대기 시간을 지정하지만 무한 대기도 가능합니다.
비동기 Bean 예:
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();
}
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();
}
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);
태스크 실패 시 원인 예외 얻기
세 프로그래밍 모델 모두 태스크 실행이 실패할 때 원인 예외를 가져오는 방법을 제공합니다. 이는 리스너를 사용하여 수행하거나(이 페이지 뒤에서 예제 제공) WorkItem 또는 Future에서 태스크 결과를 가져올 때 수행할 수 있습니다. WorkException 또는 ExecutionException이 발생되며 원래 예외가 원인으로 포함됩니다.
비동기 Bean 예:
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();
}
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();
}
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();
}
간격 이후에 실행되도록 1회용 태스크 스케줄
세 프로그래밍 모델 모두 미래 특정 시점에서 풀링된 스레드에서 실행하고 결과를 얻기 위해 기본 태스크를 스케줄하는 방법을 제공합니다.
비동기 Bean 예:
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();
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();
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);
고정 비율로 태스크 반복 스케줄 및 다음 실행 시까지의 간격 조회
CommonJ 및 Concurrency Utilities for Java EE 프로그래밍 모델은 고정 비율(예: 각 시간이 새로 시작되는 시점)로 실행되는 태스크 반복을 스케줄하는 방법을 제공합니다. 실시간 스케줄은 보장되지 않습니다. 태스크는 이 시간 이후 어느 시점에서나 시작 가능하지만 그 이전에는 시작할 수 없습니다. CommonJ 및 Concurrency Utilities for Java EE 프로그래밍 모델은 다음 실행 시까지의 지연을 계산하는 편리한 메소드도 제공합니다.
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());
Concurrency Utilities for Java EE 예:
ScheduledFuture<?> future = executor.scheduleAtFixedRate(
new PrimeFinderRunnable(120), 90, 30, TimeUnit.MINUTES);
long delay = future.getDelay(TimeUnit.SECONDS);
태스크 실행과 취소 사이의 고정 지연으로 태스크 반복 스케줄
CommonJ 및 Concurrency Utilities for Java EE 프로그래밍 모델은 하나의 실행 종료와 다음 시작 사이의 고정 간격으로 실행되도록 태스크 반복을 스케줄하는 방법을 제공합니다. 실시간 스케줄은 보장되지 않습니다. 태스크는 이 시간 이후 어느 시점에서나 시작 가능하지만 그 이전에는 시작할 수 없습니다. 비동기 Bean은 이와 동일한 동작을 얻기 위해 사용할 수 있는 Alarm에서의 재설정 메소드를 제공합니다. 세 프로그래밍 모델 모두 스케줄된 태스크의 추가 실행이 시작되는 것을 취소하는 방법을 제공합니다.
비동기 Bean 예:
AsynchScope asynchScope = abWorkManager.findOrCreateAsynchScope("MyScope");
AlarmManager alarmManager = asynchScope.getAlarmManager();
Alarm alarm = alarmManager.create(
new PrimeFinderAlarmListener(90), 50, 10);
// ... eventually cancel the alarm
alarm.cancel();
CommonJ 예:
Timer timer = timerManager.schedule(
new PrimeFinderTimerListener(90), 50, 50);
// ... eventually cancel the timer
timer.cancel();
Concurrency Utilities for Java EE 예:
ScheduledFuture<?> future = executor.scheduleWithFixedDelay(
new PrimeFinderRunnable(90), 50, 50, TimeUnit.MILLISECONDS);
// ... eventually cancel the task
future.cancel(false);
가변 간격으로 실행되도록 태스크 반복 스케줄
세 프로그래밍 모델 모두에서 반복 태스크가 다음 반복 후의 간격을 실행할 때마다 계산하는 것이 가능합니다. 비동기 Bean은 알람에 대한 재설정 메소드를 제공합니다. Concurrency Utilities for Java EE를 사용하면 다음 실행 시간을 계산하는 트리거를 플러그인할 수 있습니다. CommonJ는 이를 제공하지 않지만 CommonJ 및 다른 프로그래밍 모델에서 이전 실행이 완료될 때 태스크를 다시 스케줄할 수는 있습니다. 다음 예에서 태스크는 정확히 4시간마다 실행되도록 스케줄되며 각 실행 전에 지연은 다릅니다. 다음 실행을 재설정, 다시 스케줄 또는 계산하는 코드는 이 절에 포함된 트리거 및 기본 태스크 구현 절에 포함된 AlarmListener 및 TimerListener 구현에서 제공됩니다.
비동기 Bean 예:
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();
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();
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;
}
}
태스크 실행 일시중단 및 재개
CommonJ TimerManager는 태스크 실행을 일시중단하고 재개하는 인터페이스를 제공합니다. Concurrency Utilities for Java EE는 플러그 가능한 Trigger 메커니즘의 skipRun 메소드를 통해 더 자세하게 이 기능을 제공합니다. 단일 Trigger 인스턴스는 Trigger가 이를 지원하도록 구성된 경우 원하는 수의 태스크에 제공 가능합니다. 다음 예에서 Trigger는 단일 태스크 스케줄에 사용되도록 작성됩니다.
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();
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;
태스크 추가 실행 중지
비동기 Bean은 해당 범위 내에서 AlarmManagers로 작성된 모든 알람을 취소하는 AsynchScope를 영구 삭제하는 방법을 제공합니다. CommonJ TimerManager는 추가 실행이 시작되는 것을 중지하고 모든 실행 중인 태스크가 중지될 때까지 대기하는 인터페이스를 제공합니다. 이는 TimerManager의 모든 검색이 개별적으로 중지할 수 있는 새 인스턴스를 작성하기 때문에 가능합니다. Concurrency Utilities for Java EE에서 동일한 ManagedScheduledExecutorService가 검색 및 라이프사이클 조작(예: shutdown)에서 검색되며 isTerminated 및 awaitTermination은 허용되지 않습니다(스펙별). 그렇지만 Concurrency Utilities for Java EE를 사용하면 ManagedThreadFactory를 비관리 ScheduledExecutorService에 제공하여 유사한 동작을 얻을 수 있습니다.
비동기 Bean 예:
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();
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);
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);
컨텍스트 프록시 구성
비동기 Bean 및 Concurrency Utilities for Java EE 프로그래밍 모델을 사용하면 컨텍스트 프록시를 구성할 수 있습니다. 스레드 컨텍스트는 컨텍스트 프록시를 작성하는 스레드에서 캡처되고 그 안에 저장되어 인터페이스 메소드가 프록시에서 호출될 때 자동으로 실행 스레드에 적용되고 그 이후에 실행 스레드에서 제거됩니다. 비동기 Bean은 EventSource를 통해 이를 제공합니다. Concurrency Utilities for Java EE는 ContextService를 통해 이를 제공합니다.
비동기 Bean 예:
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");
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");
실행 스레드 트랜잭션에서 실행 중인 다중 인스턴스에 대한 컨텍스트 프록시 구성
비동기 Bean 및 Concurrency Utilities for Java EE 모두 컨텍스트 프록시의 인터페이스 메소드가 실행의 스레드 트랜잭션에서 실행되거나 현재 트랜잭션이 일시중단되고 메소드 중에 정리 트랜잭션 컨텍스트가 적용되는지 여부를 사용자가 지정할 수 있도록 합니다. 비동기 Bean의 다른 기능은 여러 개의 리스너 인스턴스가 단일 프록시로 트리거되는 것을 허용하는 점입니다. 그러나 Concurrency Utilities for Java EE에는 이 기능이 없으며 유사한 작동은 다중 인스턴스에 위임하는 랩퍼 리스너를 작성하여 수행할 수 있습니다. 다음 예에서는 모두 호출 스레드의 트랜잭션에 있는 여러 개의 리스너 인스턴스를 트리거하는 단일 프록시를 호출합니다.
비동기 Bean 예:
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();}
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();}
스레드 호출 시에 지연 실행에 대한 컨텍스트 태스크 작성
비동기 Bean을 사용하면 WorkWithExecutionContext를 작성할 수 있으며 이는 결국 태스크에 대해 직렬화 가능한 컨텍스트 프록시로 나중에 WorkManager에 제출되어 작성 스레드의 스레드 컨텍스트에서 실행 가능합니다. 호출 스레드에서 실행하려면(WorkManager의 doWork 메소드) 컨텍스트 프록시는 Concurrency Utilities for Java EE에서 유사한 동작을 수행할 수 있습니다.
비동기 Bean 예:
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();
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();
풀링된 스레드에서 지연 실행에 대한 컨텍스트 태스크 작성
비동기 Bean을 사용하면 WorkWithExecutionContext를 작성할 수 있으며 이는 결국 태스크에 대해 직렬화 가능한 컨텍스트 프록시로 나중에 WorkManager에 제출되어 작성 스레드의 스레드 컨텍스트에서 실행 가능합니다. 풀링된 스레드에서 실행하려는 경우(WorkManager의 startWork 메소드) 태스크에 대한 컨텍스트 프록시를 스레드 컨텍스트 캡처 및 전파 중복으로 인해 덜 효율적인 관리 대상 실행기에 제출하여 Concurrency Utilities for Java EE에서 수행할 수 있습니다.
비동기 Bean 예:
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();
}
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);
지연 실행에 대한 컨텍스트 태스크의 추가 옵션
지연 실행에 대해 태스크를 제출할 때 선택적으로 리스너와 시작 제한시간을 지정하고 장기간 실행되는지 여부를 표시할 수 있습니다. 시작 제한시간은 비동기 Bean에서는 매개변수로만 사용할 수 있지만 CommonJ 및 Concurrency Utilities for Java EE에 대해 시작 제한시간은 WorkListener 또는 ManagedTaskListener 내에서 구현 가능합니다.
비동기 Bean 예:
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();
}
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();
서브시스템 모니터링
비동기 Bean은 사용 가능성을 모니터하기 위해 애플리케이션이나 기타 아티팩트 사이에서 조정을 위한 메커니즘으로 SubsystemMonitor 및 SubsystemMonitorManager를 제공합니다. Concurrency Utilities for Java EE는 이에 해당하는 기능을 제공하지 않습니다. 이 기능에 대한 대체가 필요한 경우, 다른 모든 애플리케이션에 인식되는 SubsystemMonitorManager의 대응으로 작동하는 애플리케이션을 구현하여 이를 수행할 수 있습니다.
이벤트 처리
비동기 Bean은 AlarmManager, AsynchScope, EventSource, SubsystemMonitor, WorkManager, Work에서 발생하는 다양한 유형의 이벤트에 대해 리스너를 등록하는 기능을 제공합니다. 해당 이벤트 대부분은 Concurrency Utilities for Java EE에 직접적인 대응 기능을 가지고 있지 않습니다. 이벤트 및 알림에 대해 자체적인 메커니즘을 구현하는 것은 애플리케이션에서 처리해야 합니다. Concurrency Utilities for Java EE가 유사 기능을 제공하는 경우도 있습니다. AlarmManagerEvents 및 WorkEvents 대신 더 자세하게 등록되는(태스크 제출 시) ManagedTaskListener를 사용할 수 있는 경우도 있습니다.
컨텍스트 프록시의 호출 중에 발생하는 실패에 대한 이벤트 처리
비동기 Bean에서 컨텍스트 프록시는 조작 호출 시에 사용되며 조작은 선언된 예외를 표시하고 예외는 호출자에게 다시 보고되지 않습니다. 대신, 예외는 listenerExceptionThrown 이벤트에서 EventSourceEvents 리스너로 보고됩니다. Concurrency Utilities for Java EE에서 호출자는 예외를 발견하고 이를 처리할 수 있습니다.
비동기 Bean 예:
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();
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;
}