並行性プログラミング・モデルおよび非同期のプログラミング・モデルを使用するアプリケーションの Liberty へのマイグレーション
Concurrency Utilities for Java™ EE、非同期 Bean 、CommonJ Timer and Work Manager を使用するアプリケーションを WebSphere® Application Server traditional から WebSphere Application Server Liberty にマイグレーションすることができます。
非同期 Bean および CommonJ Timer and Work Manager は、Liberty では使用できません。Liberty にマイグレーションする場合は、アプリケーションを Concurrency Utilities for Java EE プログラミング・モデルに切り替える必要があります。詳しくは、Concurrency Utilities for Java EE を実装する API タスクの例を参照してください。
構成とスレッド化の違い
WebSphere Application Server traditional には、スレッド・プーリングに関連した Concurrency Utilities for Java EE 用の構成オプションがいくつかありますが、これらのオプションは Liberty では使用できません。Liberty には、すべての管理対象 executor および管理対象スケジュール executor 全体にわたって共通する、単一スレッド・プールがあります。これらの executor は Liberty コンポーネントでも共有されます。これにより、Liberty でスレッド管理を最適化することができます。WebSphere Application Server traditional では、2 つのスレッド・プールを使用して各作業マネージャーを構成することができます。一方のスレッド・プールは、できるだけ早く実行するように実行依頼されているタスク (管理対象 executor の submit/execute/invoke メソッド) のためのもので、構成可能な作業要求キューと、キュー容量が超過した場合に取るアクションが指定されています。もう一方のスレッド・プールは、スケジュール済みタスク (管理対象スケジュール executor の schedule メソッド) のためのものです。
Liberty で別のスレッド・プールを指定して Concurrency Utilities for Java EE を使用する予定の場合は、さまざまな方法で、WebSphere Application Server traditional で使用可能な構成オプションと同様の動作を実行することができます。
管理対象スレッド・ファクトリーの Java SE executor の構成
Java SE の java.util.concurrent パッケージには、スレッド・プールを特定のスレッド・ファクトリーの executor およびスケジュール executor として構成するための方法がいくつか用意されています。管理対象スレッド・ファクトリーは、管理対象外スレッド・ファクトリーの代わりに指定して、管理対象スレッドに対するタスクを実行するスレッド・プールを作成することができます。これらの executor によってプールされた管理対象スレッドは、管理対象 executor や管理対象のスケジュールされた executor とは異なり、タスクを実行依頼またはスケジュールしたときからではなく、管理対象スレッド・ファクトリーを検索したときからスレッド・コンテキストで実行されます。また、スレッド・コンテキストは、スレッドの存続期間中は管理対象スレッド上に残ります。これにより、スレッド・コンテキストの切り替えによるオーバーヘッドが削減されます。
最大作業スレッドの置き換えと作業キュー構成の例
int minThreads = 1;
int maxThreads = 2;
int workRequestQueueSize = 3;
RejectedExecutionHandler workRequestQueueFullAction =
new ThreadPoolExecutor.AbortPolicy();
ManagedThreadFactory threadFactory =
(ManagedThreadFactory) new InitialContext().lookup(
"java:comp/DefaultManagedThreadFactory");
ExecutorService executor = new ThreadPoolExecutor(
minThreads, // similar, but not exact match for coreSize
maxThreads, keepAliveTime, keepAliveTimeUnit,
new ArrayBlockingQueue<Runnable>(workRequestQueueSize),
threadFactory,
workRequestQueueFullAction);
Callable<Integer> task = new MyTask();
Future<Integer> future = executor.submit(task);
int result = future.get();
最大アラーム・スレッドの置き換えの例
int maxAlarms = 2;
ManagedThreadFactory threadFactory =
(ManagedThreadFactory) new InitialContext().lookup(
"java:comp/DefaultManagedThreadFactory");
ScheduledExecutorService executor =
Executors.newScheduledThreadPool(maxAlarms, threadFactory);
Callable<Integer> task = new MyTask();
ScheduledFuture<Integer> future = executor.schedule(
task, 50, TimeUnit.SECONDS);
int result = future.get();
作業タイムアウトの適用
WebSphere Application Server traditional では、できるだけ早く実行するように実行依頼されているタスク (submit/execute/invoke メソッド) に適用する作業タイムアウトを構成することができます。割り当てられた作業タイムアウトよりもタスクの実行時間が長い場合、そのタスクを中断してタスクを取り消そうとする試みが行われます。Liberty には構成オプションとしての作業タイムアウトはありませんが、管理対象タスク・リスナーによるタスクを実行依頼することで同様の動作を実装できます。このリスナーは、taskStarting 通知に応答して、そのタスクの Future を取り消すタスクをスケジュールします。管理対象タスク・リスナーが使用できない場合は、代わりにスレッド・プール executor を前述の例のように使用すると、スレッド・プール executor の beforeExecute メソッドをオーバーライドして、実行スレッドを中断するタスクをスケジュールすることができます。
作業タイムアウトの置き換えの例
ManagedExecutorService executor =
(ManagedExecutorService) new InitialContext().lookup(
"java:comp/DefaultManagedExecutorService");
Callable<Long> slowTask = new SlowTask();
slowTask = ManagedExecutors.managedTask(
slowTask, new WorkTimeout(5, TimeUnit.SECONDS));
Future<Long> future = executor.submit(slowTask);
try {
long result = future.get(1, TimeUnit.MINUTES);
// task successful...
} catch (CancellationException x) {
// task was canceled, possibly due to timeout
}
public class WorkTimeout implements ManagedTaskListener {
private final long timeout;
private final TimeUnit unit;
public WorkTimeout(long timeout, TimeUnit unit) {
this.timeout = timeout;
this.unit = unit;
}
public void taskSubmitted(Future<?> future,
ManagedExecutorService executor, Object task) {}
public void taskStarting(final Future<?> future,
ManagedExecutorService executor, Object task) {
try {
ScheduledExecutorService scheduledExecutor =
(ScheduledExecutorService) new InitialContext().lookup(
"java:comp/DefaultManagedScheduledExecutorService");
scheduledExecutor.schedule(new Runnable() {
@Override
public void run() {
if (!future.isDone())
future.cancel(true);
}
}, timeout, unit);
} catch (NamingException x) {
x.printStackTrace(System.out);
}
}
public void taskAborted(Future<?> future, ManagedExecutorService executor, Object task, Throwable x) {}
public void taskDone(Future<?> future, ManagedExecutorService executor, Object task, Throwable x) {}
}