【コラム】

Java API、使ってますか?

21 Java EE環境でのスレッドプログラミングを可能にするJSR 237

21/60

JSR 237: Work Manager for Application Servers

つい先日、次期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のWork Managerを試す

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

図1 BEA Weblogic ServerにおけるWorkManagerの登録

続いてJava EEコンポーネントのDeployment Descriptorファイル(Servletの場合web.xml、EJBの場合ejb-jar.xml)にリソース参照の設定を追加する。今回はServletを使うのでweb.xmlにリスト1のように記述する。

リスト1 web.xml - リソース参照の設定を追加

    <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を返す場合、そのスレッドはデーモンスレッドとして動作する。

リスト2 SampleWork.java - Workの実装クラス。単一スレッドとして動作する

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のどれかひとつが終了するまで待ち受ける。

リスト3 WorkServlet.java - Work Managerを利用したサーブレットの例

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のようになる。

リスト4 web.xml - サーブレットの設定を追加

<?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ページ側のデザインは省略した。

プロンプト1 WorkServletの実行結

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として標準化が進められている。

21/60

インデックス

連載目次
第60回 どうなる? 今後のJavaプラットフォーム(Java SE編)
第59回 どうなる? 今後のJavaプラットフォーム(Java EE編)
第58回 Java SE 7の要注目機能"クロージャ"はどうなるのか その6
第57回 Java SE 7の要注目機能"クロージャ"はどうなるのか その5
第56回 Java SE 7の要注目機能"クロージャ"はどうなるのか その4
第55回 Java SE 7の要注目機能"クロージャ"はどうなるのか その3
第54回 Java SE 7の要注目機能"クロージャ"はどうなるのか その2
第53回 Java SE 7の要注目機能"クロージャ"はどうなるのか
第52回 Early Draftが公開されたJSF 2.0
第51回 EJBから独立したJava Persistence 2.0
第50回 モバイルJavaの新しい潮流となるか - MSA 2.0のドラフト公開
第49回 やっぱり基本はServlet - Servlet 3.0のEarly Draftを読む
第48回 JOGLで3Dプログラミング その4
第47回 JOGLで3Dプログラミング その3
第46回 JOGLで3Dプログラミング その2
第45回 JOGLで3Dプログラミング
第44回 JARファイルを効率的にネットワーク転送するためのPack200形式
第43回 Early Draftで把握するEJB 3.1の新機能
第42回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その2
第41回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その1
第40回 リソースアダプタによる接続の仕組み
第39回 JCAを利用したシステム間接続
第38回 Java EEと外部システムの接続性を支えるJCAがバージョンアップ
第37回 Javaのモジュラリティ強化を担う"スーパーパッケージ"とは
第36回 JSR 308対応のコンパイラを試す
第35回 公開されたJSR 308のEarly Draftを検証する
第34回 スクリプト言語とJavaを結びつけるJSR 223
第33回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その2
第32回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その1
第31回 Javaの文法がそのまま使えるスクリプト言語"BeanShell"
第30回 Javaアプリケーションにオブジェクトのキャッシュ機構を提供するJCache API
第29回 Javaアプリケーションからのリソース管理を可能にするJSR 284
第28回 XMLデータソースへの問い合わせはJSR 225で
第27回 Portlet Specification 2.0をもっと手軽に利用する
第26回 次期Javaポートレット仕様となるJSR 286
第25回 JSFとポートレットをつなげるJSR 301
第24回 Webサービス向けのポートレット仕様「WSRP」
第23回 高い相互運用性を実現するポートレットAPI - JSR 168
第22回 Java EE環境でタスクのスケジューリングを可能にするJSR 236
第21回 Java EE環境でのスレッドプログラミングを可能にするJSR 237
第20回 音声認識/合成のためのAPI - Java Speech APIとJSR 113
第19回 JSR 291でJavaプラットフォームにダイナミックコンポーネントモデルを導入
第18回 JAX-RSで簡単RESTful - JSR 311
第17回 待望のServlet 3.0がJSRに登場 - JSR 315
第16回 アノテーションを使ってバグ退治 - JSR 305
第15回 アノテーションをさらに広い範囲で利用可能にするJSR 308
第14回 Webアプリケーション開発の要となるか - JSF 2.0がJSRに登場
第13回 Webサービス経由でのJMX Agentへの接続を可能にするJSR 262
第12回 Javaアプリケーションのモジュール化をサポートするJava Module System
第11回 "NIO.2"がやってきた - JSR 203: More New I/O APIs for the Java Platform
第10回 JSR 295: Beans Bindingの参照実装を試す
第9回 けっこう便利! 単位を扱うAPI -- JSR 275: Units Specification
第8回 アノテーションでバリデーション - JSR 303: Bean Validator
第7回 Swing開発の救世主となるか - Swing Application Framework
第6回 JavaBeansのプロパティを同期させるバインディングAPI
第5回 誰よりも早く"Java SE 7"を睨む
第4回 日時情報の取り扱いを改善する JSR 310: Date and Time API
第3回 古いAPIも進化している!? - JSR 919: JavaMail 1.4
第2回 JSR 1 リアルタイムJava仕様
第1回 JCPによって進められるJava関連技術の標準化

もっと見る

提供:マイナビ

会員登録はこちら

大学・大学院・短大・専門学生向けの就職情報サイト「マイナビ2010」「マイナビ2009」に今すぐ登録しよう!  大手企業からベンチャー企業までの約13,000社の企業情報を公開、エントリーが可能です。2010年卒予定の方は「マイナビ2010」に、2009年卒予定の方は「マイナビ2009」に登録してください。

毎日コミュニケーションズはプライバシーマークを取得しています。



人気記事

一覧

イチオシ記事

新着記事