8

短い質問: Tomcat 6 アプリ内で (別の) スレッドプールを実行するにはどうすればよいですか?

スレッド プールを実行するための最適なソリューションは何ですか?

長い質問:
ここでは簡単な必要があります。
Web クライアントが応答を待機できるようにしながら、一部のデータについてデータベースをポーリングします (長いポーリング接続)。
このデータがデータベースで利用可能になったら、関連するクライアントに返信します。

そうは言っても、現時点ではどのフレームワークにも飛び込むことは避けたいquartz schedulerと思っています (多分?)。

したがって、結論として、バックグラウンドでジョブを実行するにはスレッド プールが必要になります。

それで、Thread私が使おうとしているものが(実際にはRunnable)である場合、どのクラスがそれをすべて整理できますか?解決策のようなものはありますThreadPoolか?推奨事項はありますか?

4

3 に答える 3

17

あなたの短い質問に答える:

JVM では、スレッド プールはインターフェイスの背後で抽象化されjava.util.concurrent.ExecutorServiceます。このインターフェースにはさまざまな実装がありますが、ほとんどの場合、このインターフェースのメソッドで十分です。

特定のスレッド プールを作成するには、次のjava.util.concurrent.Executorsクラスを参照してください: http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.htmlExecutorServiceには、インターフェイス のさまざまな実装を作成するための静的ファクトリ メソッドが含まれています。 . メソッドnewFixedThreadPool(int threadsNumber)に興味があるかもしれません。newCachedThreadPool

JVMの一般的な情報についてExecutorsは、次の Oracle のチュートリアルを参照してください。 http://docs.oracle.com/javase/tutorial/essential/concurrency/executors.html

したがって、ExecutorServiceTomcat でスレッド プール ( ) を使用するには、次の手順を実行する必要があります。

.1. まだ完了していない場合web.xmlは、インターフェイスのインスタンス(Web アプリケーションへのエントリ ポイントのように機能します) を作成して登録します。javax.servlet.ServletContextListener

.2. メソッドでは、 (スレッドプール)contextInitialized(ServletContextEvent)のインスタンスを作成し、それを属性マップに保存して、webapp のどのポイントからでもアクセスできるようにします。ExecutorServiceServletContext

// following method is invoked one time, when you web application starts (is deployed)
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
    // ...
    final int numberOfThreads = ...;
    final ExecutorService threadPool = Executors.newFixedThreadPool(numberOfThreads); // starts thread pool
    final ServletContext servletContext = servletContextEvent.getServletContext();
    servletContext.setAttribute("threadPoolAlias", threadPool);
    // ...
}

// following method is invoked one time when your web application stops (is undeployed)
public void contextDestroyed(ServletContextEvent servletContextEvent) {
    // following code is just to free resources occupied by thread pool when web application is undeployed
    final ExecutorService threadPool = (ExecutorService) servletContextEvent.getServletContext().getAttribute("threadPoolAlias");
    threadPool.shutdown();
}

.3. メソッドのどこか、または webapp のどこか (webapp からほとんどどこ へのServlet.service参照も取得できるはずです):ServletContext

Callable<ResultOfMyTask> callable = new Callable<ResultOfMyTask>() {
    public ResultOfMyTask call() {
        // here goes your task code which is to be invoked by thread pool 
    }
};

final ServletContext servletContext = ...;
final ExecutorService threadPool = (ExecutorService) servletContext.getAttribute("threadPoolAlias");
final Future<ResultOfMyTask> myTask = threadPool.submit(callable);;

myTask への参照を保存する必要があり、他のスレッドからクエリを実行して、終了したかどうかと結果を確認できます。

お役に立てれば...

于 2012-06-15T14:56:36.553 に答える
0

単純なバックグラウンド タスクの場合、スレッド プールはまったく必要ありません。あなたがする必要があるのは、次のとおりです。

  1. スレッドを立ち上げる
  2. バックグラウンド プロセスを停止する必要があるかどうかを確認する
  3. データベースをポーリングさせる
  4. 新しくポーリングされたデータをアクセス可能な場所に保存する
  5. バックグラウンド プロセスを停止する必要があるかどうかを確認する
  6. 寝る
  7. 手順 2 ~ 7 を繰り返します

ServletContextListener実装するクラスで定義した上記の手順を実行するスレッドを起動する を記述しますRunnable。メソッドで、contextDestroyed上記の #2 と #5 で示したチェックをトリガーするフラグを設定し、Thread.interruptスレッドが終了するように呼び出します。

バックグラウンド タスクは、クライアントにメッセージを同期的に送信しようとするべきではありません。代わりに、モニターなどの他のメカニズムを使用して待機中のポーラーに通知Object.notifyする (現在のステータスをチェックしているクライアントをブロックしたくないため、これは実際には意味がありません)、何らかのタイムスタンプを更新するか、ポーリングを行うだけです。クライアントは #4 で利用可能な現在のデータを確認します。

于 2012-06-15T20:10:27.350 に答える
0

ユース ケースでは、Java プラットフォームで利用可能な Timer と TimerTask を利用して、バックグラウンド タスクを定期的に実行できます。

import java.util.Timer;
import java.util.TimerTask;

TimerTask dbTask = new TimerTask() {
    @Override
    public void run() {
        // Perform Db call and do some action
    }
};

final long INTERVAL = 1000 * 60 * 5; // five minute interval

// Run the task at fixed interval
new Timer(true).scheduleAtFixedRate(dbTask, 0, INTERVAL);

タスクの完了に 5 分以上かかる場合、後続のタスクは並行して実行されないことに注意してください。代わりに、それらはキューで待機し、前のものが終了すると次々と急速に実行されます。

このコードをシングルトン クラスにラップして、起動サーブレットから呼び出すことができます。

一般に、これらの種類の定期的なバックグラウンド ジョブをサーブレット コンテナーの外部で実行することをお勧めします。これは、HTTP 要求を処理するために効率的に使用する必要があるためです。

于 2012-06-15T14:11:57.430 に答える