【コラム】
つい先日、次期Java EEプラットフォーム仕様となるJSR 316がExecutive Committieeによる最初の承認投票を賛成多数で通過した。JSR 316では、Java EE 6で新しく追加されるAPIとしてJSR 196、JSR 236、JSR 237、JSR 299、JSR 311などを挙げている。そのうちJSR 311については本連載でも第18回で取り上げた。今回は「JSR 237: Work Manager for Application Servers」を紹介したい。
JSR 237は、ひとことで言ってしまえばJava EE環境でスレッドプログラミングを可能にするためのAPIである。Javaでスレッドプログラミングを行うためには、通常java.lang.Runnableインタフェースやjava.lang.Threadクラスを使用する。しかし、Java EE環境では事情が違ってくる。サーブレットやEJBの管理対象環境ではこれらのAPIによるスレッド処理には制約があり、原則として推奨されていないからだ。
JSR 237では、Java EE環境においても安全にスレッドを使用した非同期並列処理を実現できる手段を提供する。この仕様の策定は、IBMとBEA Systemsが中心になって行っている。両社はJ2EEアプリケーションサーバのプログラミングモデルとAPIの仕様を共同で策定するCommonJプロジェクトを進めており、その一環として非同期並列処理のための「Timer and Work Manager for Application Servers」を定めた。JSR 237は、そのうちの"Work Manager"の部分を標準化する目的でJCPに提出されたものである。
JSR 237のドラフトはまだ公開されていないため、今回はCommonJの実装を使ってJava EE環境上でスレッドプログラミングを行ってみる。
CommonJの「Timer and Work Manager for Application Servers」仕様やインタフェース実装はBEAによるプロジェクトサイトまたはIBMによるプロジェクトサイトで公開されている。また、これらのAPIは「IBM WebSphere Application Server V6.0以降」および「BEA WebLogic Server 9.0以降」に実装されているほか、オープンな実装としてはGlobus Toolkitなどがある。
CommonJのWork Managerのクラス/インタフェースはcommonj.workパッケージ以下に用意されている。ここにjava.lang.RunnableをextendsしたWorkインタフェースが定義されており、これがJava EE用のThreadクラスとも言うべきものになる。したがってスレッドの処理はWorkインタフェースをimplementsしたクラスのrun()メソッドに記述すればよい。
スレッドの実行はWorkManagerのschedule()メソッドにWorkオブジェクトを渡すことで行う。WorkManagerオブジェクトはアプリケーションサーバよりJNDI経由で取得する。したがって、まず準備段階としてアプリケーションサーバのネーミングサービスにWorkManagerオブジェクトを登録しなくてはならない。WorkManagerオブジェクトの登録の仕方は各アプリケーションサーバによって異なるので、それぞれのマニュアルを参考にしてほしい。たとえばBEA Weblogic Serverの場合は、管理コンソールの[Environment]-[Work Managers]メニューからWorkManagerの作成と登録が行える(図1)。
続いてJava EEコンポーネントのDeployment Descriptorファイル(Servletの場合web.xml、EJBの場合ejb-jar.xml)にリソース参照の設定を追加する。今回はServletを使うのでweb.xmlにリスト1のように記述する。
<resource-ref>
<res-ref-name>wm/MyWorkManager</res-ref-name>
<res-type>commonj.work.WorkManager</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
Workインタフェースの実装クラスSampleWorkはリスト2のように、呼び出されたら指定されたミリ秒だけスリープするスレッドとした。なおisDaemon()メソッドがtrueを返す場合、そのスレッドはデーモンスレッドとして動作する。
package sample;
import commonj.work.Work;
public class SampleWork implements Work {
protected String name = "noname";
protected long time = 1000;
public SampleWork(String name, long time) {
this.name = name;
this.time = time;
}
public void release() {
System.out.println("MyWork: " + this.name + " をリリース.");
}
public boolean isDaemon() {
return false;
}
public void run() {
try {
System.out.println("MyWork: " + this.name + " を開始します.");
System.out.println("MyWork: " + this.name
+ " を " + this.time + " ミリ秒スリープします.");
Thread.sleep(this.time);
System.out.println("MyWork: " + this.name + " を終了します.");
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
最後にJNDI経由でWorkManagerを取得してSampleWorkの処理を実行するサーブレットWorkServletを作成する。ここではリスト3のようにinit()メソッドにおいてInitialContextを利用してWorkManagerオブジェクトを取得し、これを用いて2つのSampleWorkを実行するようにした。
WorkManagerのschedule()メソッドはWorkオブジェクトの状態を保持するWorkItemオブジェクトを返す。WorkItemの集合をwaitForAll()メソッドに渡すと、Thread.join()のように対象となる全てのWorkが完了するまで待ち受けるようになる。第2引数にはタイムアウト時間を指定する。ちなみにwaitForAny()メソッドの場合、対象となるWorkのどれかひとつが終了するまで待ち受ける。
package sample;
import commonj.work.WorkItem;
import commonj.work.WorkManager;
import commonj.work.WorkException;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.*;
import javax.servlet.http.*;
public class WorkServlet extends HttpServlet {
WorkManager myWorkManager = null;
@Override
public void init() throws ServletException {
try {
InitialContext ic = new InitialContext();
// WorkManagerオブジェクトをJNDI経由で取得
this.myWorkManager
=(WorkManager)ic.lookup("java:comp/env/wm/MyWorkManager");
} catch(NamingException e) {
e.printStackTrace();
}
}
protected void processRequest
(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
SampleWork work1 =null;
SampleWork work2 =null;
try {
// Workオブジェクトの生成
work1 = new SampleWork("ワーク1", 5000);
work2 = new SampleWork("ワーク2", 8000);
System.out.println("WorkServlet: Workを開始します.");
// WorkオブジェクトをWorkManagerオブジェクトに登録
WorkItem workItem1 = this.myWorkManager.schedule(work1);
WorkItem workItem2 = this.myWorkManager.schedule(work2);
List workItemList=new ArrayList();
workItemList.add(workItem1);
workItemList.add(workItem2);
if (this.myWorkManager.waitForAll(workItemList, WorkManager.INDEFINITE)) {
System.out.println("WorkServlet: 全てのWorkが終了しました.");
}
else {
System.out.println("WorkServlet: タイムアウトしました.");
}
}
catch (WorkException ex) {
ex.printStackTrace();
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
}
web.xmlにはServletを有効にするための設定を追加し、最終的にはリスト4のようになる。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<resource-ref>
<res-ref-name>wm/MyWorkManager</res-ref-name>
<res-type>commonj.work.WorkManager</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
<servlet>
<servlet-name>WorkServlet</servlet-name>
<servlet-class>sample.WorkServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>WorkServlet</servlet-name>
<url-pattern>/WorkServlet</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
</web-app>
完成したらコンパイルしてWARファイルにまとめ、アプリケーションサーバにデプロイする。ブラウザからWorkServletサーブレットにアクセスすると、アプリケーションサーバの標準出力にはプロンプト2.6のように表示されるはずだ。なお、今回は簡略化のためWebページ側のデザインは省略した。
WorkServlet: Workを開始します.
MyWork: ワーク1 を開始します.
MyWork: ワーク1 を 5000 ミリ秒スリープします.
MyWork: ワーク2 を開始します.
MyWork: ワーク2 を 8000 ミリ秒スリープします.
MyWork: ワーク1 を終了します.
MyWork: ワーク2 を終了します.
WorkServlet: 全てのWorkが終了しました.
次回はCommonJで実装されているもうひとつのAPIである"Timer"に関する機能を紹介したい。こちらはJSR 236: Timer for Application Serversとして標準化が進められている。
提供:マイナビ
大学・大学院・短大・専門学生向けの就職情報サイト「マイナビ 2009」「毎日就職ナビ 2008」に今すぐ登録しよう! 大手からベンチャー企業までの企業情報を公開、エントリーが可能です。2009年卒予定の方は「マイナビ 2009」に、2008年卒予定の方は「毎日就職ナビ 2008」に登録してください。
毎日コミュニケーションズはプライバシーマークを取得しています。
提供:マイナビ
大学・大学院・短大・専門学生向けの就職情報サイト「マイナビ2010」「マイナビ2009」に今すぐ登録しよう! 大手企業からベンチャー企業までの約13,000社の企業情報を公開、エントリーが可能です。2010年卒予定の方は「マイナビ2010」に、2009年卒予定の方は「マイナビ2009」に登録してください。
毎日コミュニケーションズはプライバシーマークを取得しています。
| Java EE 6、最初の承認プロセスを通過 - ASFはついに反対票 [2007/7/18] |
| トマトを食べれば痩せられる!? -京大ら、新発見の成分で肥満改善効果を実証 [21:00 2/10] |
| JAXA、液体シリコン中に残存する共有結合を観察 -大口径ウェハの実現に期待 [20:11 2/10] |
| NEDOなど、熱膨張が小さな樹脂複合材料ペレットの量産化に成功 [19:22 2/10] |
| 理研、一般顕微鏡を蛍光顕微鏡に強化できるアダプタを試作して性能を実証 [19:15 2/10] |
| 天の川のブラックホールが小惑星を飲み込んでいる - NASAが発表 [18:08 2/10] |
|
[西部警察]大門のサングラスは照れ隠し? 制作担当者が語る舞台裏 [09:00 2/11] エンタメ |
|
9ストーリーズ ~バレンタインのエピソード~ [08:05 2/11] キャリア |
|
RX-7改フェラーリ登場!/マジックRX-7XX 【大阪オートメッセ2012】 [08:04 2/11] キャリア |
|
【連載】鉄道トリビア 第137回 山手線と京浜東北線から●●●が消えた!? [08:00 2/11] ライフ |
|
JRグループ、「周遊きっぷ」を見直し - 19の周遊ゾーンが3/31で販売終了に [07:30 2/11] ライフ |