web-dev-qa-db-ja.com

Jboss Java EEコンテナとExecutorService

ExecutorServiceを使用して複数のジョブを並列処理するスタンドアロンのJavaアプリ

 ExecutorService es = Executors.newFixedThreadPool(10);

EJB Bean内で同じソリューションを再利用したいのですが、通常はJava EEコンテナーを残してすべてのスレッドリソースを制御するため、ThreadPoolを正しく初期化する方法はわかりません。同じコードを使用するだけですか、Jbossマネージドスレッドプールを取得する別の正しい方法がありますか?

27
emeraldjava

EJBでこれを行う正しい方法は、Concurrency Utils API(Java EE7)の一部であるManagedExecutorServiceを使用することです。エンタープライズコードでJava.util.concurrentの一部であるExecutorServiceを使用しないでください。

ManagedExecutorServiceを使用することにより、新しいスレッドが作成され、コンテナーによって管理されます。

次の例は、私のサイト here からのものです。

ManagedExecutorServiceを使用して新しいスレッドを作成するには、最初にCallableを実装するタスクオブジェクトを作成します。 call()メソッド内で、別のスレッドで実行する作業を定義します。

public class ReportTask implements Callable<Report> {

    Logger logger = Logger.getLogger(getClass().getSimpleName());

    public Report call() {
        try {
            Thread.sleep(3000);
        catch (InterruptedException e) {
            logger.log(Level.SEVERE, "Thread interrupted", e);
        }
        return new Report();
    }
}

次に、ManagedExecutorServiceのsubmit()メソッドに渡すことでタスクを呼び出す必要があります。

@Stateless
public class ReportBean {

    @Resource
    private ManagedExecutorService executorService;

    public void runReports() {
        ReportTask reportTask = new ReportTask();
        Future<Report> future = executorService.submit(reportTask);
    }
}
30
Chris Ritchie

必須の警告:独自のスレッドをJava EEアプリサーバー(Tomcatを含む)で作成することは、パフォーマンス上の大きな問題になる可能性があり、ほとんどの場合、コンテナー機能を妨げるため、推奨されませんJNDIとして、動作中。新しいスレッドは、それらがどのアプリケーションに属しているかを知らず、スレッドコンテキストクラスローダーは設定されず、他の多くの隠れた問題があります。

幸いなことに、Java EEサーバーを取得して、Java EE 6 @Asynchronousおよびこの巧妙なデザインパターン。任意のJava EE 6認定サーバーに移植可能。

アプリケーションでこのEJBを作成します。

package org.superbiz;

import javax.ejb.Asynchronous;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import Java.util.concurrent.Callable;
import Java.util.concurrent.Executor;

@Stateless(name="Executor")
public class ExecutorBean implements Executor {

    @Asynchronous
    @Override
    public void execute(Runnable command) {
        command.run();
    }
}

次に、プレーンな依存性注入を介して、アプリケーション内の他の場所でこのBeanを参照できます(参照コンポーネントがサーブレット、リスナー、フィルター、他のEJB、JSF管理Beanの場合)。

@EJB
private Executor executor;

その後、通常どおりExecutorを使用します。

コンポーネントが別のJava EEコンポーネントではない場合、次の方法でBeanを検索できます。

InitialContext initialContext = new InitialContext();
Executor executor = (Executor) initialContext.lookup("Java:module/Executor");
26
David Blevins

さて... Davidのソリューションは、次の理由でうまくいきませんでした。

  1. コンパイラは、Java.util.concurrentが許可されていないことを回避していました...これは、JBOSSスコープで意味をなします。
  2. また:public STATIC class ...?これを読んでください: Javaでクラスを静的として宣言できないのはなぜですか?

私がやったことは次のとおりです。
私のインストール:
-JBOSS AS 7.1.1
-Java 1.6
-RHEL
- Gradle および Arquillian を使用して例を実行する:

@Stateless
public class ExecutorBean {
    @Asynchronous
    public void execute(Runnable command) {
        command.run();    
    }
}

次に、クライアントは次のようになります。

@EJB ExecutorBean eb;
@Test
public void testExecutorBean() {
    eb.execute(new YourCustomizedRunnableWhichDoesALotOfUsefulStuff());
    assertFalse(!true);
}

ただし、注意してください。standalone.xml(または一般的に言えばJBOSSの設定ファイル)には「スレッドプール」というセクションがあります。(JBOSSASを使用する場合)それを見て、値をいじってください。 arquillianテストでスレッドを使用すると、キープアライブ時間が非常に長くなりますが、killされたスレッドを取得します。これは、arquillianのマイクロデプロイの方法と関係があると思います。テストが実行されている間...少なくとも私はそれを観察していると思いますが、一方で、すべての終了したスレッドは実際にはタスク/操作を完了したという意味でうまく動作しました。

この投稿がお役に立てば幸いです!

5
easyDaMan

EE7より前は、JSR 237のWorkManagerを使用する必要がある場合があります

http://docs.Oracle.com/javaee/1.4/api/javax/resource/spi/work/WorkManager.html

この仕様は現在取り下げられていますが、一部のアプリサーバーはまだ実装しています。 WebSphere 8.5でIBMの実装を使用します- IBM WorkManager 。これは完全に管理されたリソースであり、管理コンソールで利用できます。 Oracleとのインターフェイス互換性がないことに注意してください。

IBMバージョンの例を次に示します。

@Resource(lookup = "wm/default")
WorkManager workManager;

public void process() {
    try {
        ArrayList<WorkItem> workItems = new ArrayList<WorkItem>();
        for (int i = 0; i < 100; i++) {
            // submit 100 jobs
            workItems.add(workManager.startWork(new Work() {
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + " Running");
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void release() {
                    System.out.println(Thread.currentThread().getName() + " Released");
                }
            }));
        }
        // wait for all jobs to be done.
        workManager.join(workItems, WorkManager.JOIN_AND, 100000);
    } catch (WorkException e) {
        e.printStackTrace();
    }
}

また、 Commonj Workmanager を認識しています。

2
Vlad

JBossを使用している場合、org.jboss.seam.async.ThreadPoolDispatcherを使用できます。

ThreadPoolDispatcherは完全に管理されています。

他の便利なマネージクラスについては、パッケージorg.jboss.seam.asyncをご覧ください。

0
marciowb