29

ExecutorServiceを使用して多数のジョブを並行して処理するスタンドアロンのJavaアプリがあります

 ExecutorService es = Executors.newFixedThreadPool(10);

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

4

5 に答える 5

34

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

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

次の例は、ここの私のサイトから抜粋したものです。

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);
    }
}
于 2013-10-16T13:20:30.390 に答える
27

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

@Asynchronous幸い、JavaEEサーバーにJavaEE6とこの巧妙なデザインパターンを介してスレッドプールを管理させる方法があります。JavaEE6認定サーバーに移植可能。

アプリケーションでこの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通常どおりに使用します。

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

InitialContext initialContext = new InitialContext();
Executor executor = (Executor) initialContext.lookup("java:module/Executor");
于 2012-12-19T04:33:10.653 に答える
5

ええと...Davidの解決策は、次の理由で私にはうまくいきませんでした。

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

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

@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の設定ファイルには「thread-pools」セクションがあります。それを見て(JBOSSASを使用している場合)、そこにある値をいじくりまわしてください。 arquillianテストでスレッドを使用すると、キープアライブ時間が非常に長いにもかかわらず、スレッドが強制終了されます。これは、arquillianのマイクロデプロイの方法に関係していると思います。arquillianが終了すると、実行中の未完了のスレッドがすべて強制終了されます。テストが実行されている間...少なくともそれは私が観察していることだと思います。一方、完成したすべてのスレッドは、タスク/操作を完了したという意味で実際に正常に動作しました。

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

于 2013-05-03T13:24:29.797 に答える
3

EE7より前は、JSR237のWorkManagerを使用することをお勧めします。

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

この仕様は現在廃止されていますが、一部のアプリサーバーで実装されています。WebSphere8.5でIBMの実装を使用しています-IBMWorkManager。これは完全に管理されたリソースであり、管理コンソールで利用できます。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();
    }
}

また、私はCommonjWorkmanagerを知っています。

于 2013-11-28T09:18:20.973 に答える
0

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

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

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

于 2017-04-27T15:45:49.757 に答える