Tomcatのサーブレットからスレッドを生成するための推奨される方法は何ですか
おそらく繰り返し!私はサーバーとしてTomcatを使用していますが、確定的な結果でサーブレットにスレッドを生成する最良の方法を知りたいです。サーブレットアクションから実行時間の長い更新を実行していますが、リクエストを完了し、更新をバックグラウンドで実行したいと考えています。 RabbitMQのようなメッセージングミドルウェアを追加する代わりに、バックグラウンドで実行して独自の時間で終了するスレッドを生成できると考えました。リソースを適切に管理するために、サーバーが生成したスレッドをサーバーが終了させる他のSOスレッドを読み込みました。
Tomcatを使用するときにスレッド、バックグラウンドジョブを生成する推奨方法はありますか。アプリケーションにはSpring MVCも使用しています。
最も安全な方法は、アプリケーションワイドスレッドプールと最大量のスレッドを使用することです。これにより、必要なときにタスクがキューに入れられます。 ExecutorService
はこれに非常に役立ちます。
アプリケーションの起動時またはサーブレットの初期化時に Executors クラスを使用します。
executor = Executors.newFixedThreadPool(10); // Max 10 threads.
次に、サーブレットのサービス中(興味がない場合は結果を無視できます):
Future<ReturnType> result = executor.submit(new CallableTask());
最後に、アプリケーションのシャットダウンまたはサーブレットの破棄中に:
executor.shutdownNow(); // Returns list of undone tasks, for the case that.
Foo-CommonJ のようなCommonJ WorkManager(JSR 237)実装を使用できます。
CommonJ-JSR 237タイマーおよびワークマネージャー
Foo-CommonJは、JSR 237 TimerおよびWorkManagerの実装です。 独自の実装が付属していないコンテナ(主にTomcatなどのプレーンなサーブレットコンテナ)で使用するように設計されています。また、WorkManager APIを持たない、またはJBossのような非標準APIを使用する完全に機能するJava EEアプリケーションサーバーで使用することもできます。
WorkManagerを使用する理由
一般的な使用例は、サーブレットまたはJSPが複数のソースからデータを集約し、1ページに表示する必要があることです。 J2EEコンテナのような管理された環境で独自のスレッドを作成することは不適切であり、アプリケーションレベルのコードで実行しないでください。この場合、WorkManager APIを使用してデータを並行して取得できます。
CommonJのインストール/デプロイ
JNDIリソースの展開はベンダーに依存します。この実装には、
javax.naming.spi.ObjectFactory
インターフェースを実装するFactoryクラスが付属しており、最も一般的なコンテナーに簡単にデプロイできます。 JBossサービスとしても利用可能です。もっと...
更新:明確にするために、 Java EEプレビュー)の同時実行ユーティリティ (これはJSR-236およびJSR-237の後継者)は、アンマネージドスレッドについて次のように書いています。
2.1コンテナ管理スレッドと非管理スレッド
Java EEアプリケーションサーバーは、管理を集中化し、アプリケーションコンポーネントが不要なリソースを消費しないように保護するために、リソース管理が必要です。これは、リソースをプールし、リソースのライフサイクルを管理することで実現できます。 Java
Java.util.concurrency
API、Java.lang.Thread
、Java.util.Timer
などのSE同時実行ユーティリティを使用して、サーブレットやEJBなどのサーバーアプリケーションコンポーネントで問題があるのは、コンテナとサーバーがこれらのリソースの知識を持っていないためです。
Java.util.concurrent
APIを拡張することにより、アプリケーションサーバーとJava EEコンテナは使用されるリソースを認識し、非同期の適切な実行コンテキストを提供できます。実行する操作。これは、主に
Java.util.concurrent.ExecutorService
インターフェイスの管理されたバージョンを提供することで実現されます。
新しいIMOはありません。「古い」問題は同じです。アンマネージスレッドは依然としてアンマネージスレッドです。
- これらはアプリケーションサーバーに認識されておらず、Java EEコンテキスト情報にアクセスできません。
- アプリケーションサーバーの背面にあるリソースを使用でき、その数とリソースの使用を制御する管理機能がないと、アプリケーションサーバーがリソースを障害から回復したり正常にシャットダウンしたりすることができます。
参照資料
Springは、spring-schedulingを介して非同期タスク(長時間の場合)をサポートします。 Javaスレッドを直接使用する代わりに、Quartzで使用することをお勧めします。
リコース:
私はそれが古い質問であることを知っていますが、人々は常に質問し続け、この種のこと(サーブレット要求の処理中に明示的にスレッドを生成する)を常に試みています...それは非常に欠陥のあるアプローチです-複数の理由から。 .. Javaそのような慣習に眉をひそめるEEコンテナは、一般的には正しいが...
最も重要なことは、サーブレットが同時に受信する同時リクエストの数を予測できないことです。定義上、Webアプリケーション、サーブレットは、指定されたエンドポイントで一度に複数のリクエストを処理できることを意味します。特定の数の同時スレッドを明示的に起動するように処理ロジックを要求するプログラミングを行っている場合、使用可能なスレッドが不足してアプリケーションが停止するという避けられない状況に直面する危険があります。タスクエグゼキュータは、有限の妥当なサイズに制限されているスレッドプールで動作するように常に構成されています。ほとんどの場合、10〜20以下です(タスクの性質、競合するリソース、サーバー上のプロセッサの数などに応じて、ロジックを実行するスレッドが多すぎることは望ましくありません)。 、リクエストハンドラー(例:MVCコントローラーメソッド)は、1つ以上の@Asyncアノテーション付きメソッドを呼び出します(この場合、Springはタスクエグゼキューターを抽象化して簡単にします)、またはタスクエグゼキューターを明示的に使用します。コードが実行されると、利用可能なスレッドをプールから取得し始めます。すぐにフォローアップリクエストをせずに、一度に1つのリクエストを常に処理している場合は問題ありません。 (その場合、問題を解決するために間違ったテクノロジーを使用しようとしている可能性があります。)ただし、リクエストでエンドポイントを攻撃している可能性のある任意の(または既知の)クライアントに公開されるWebアプリケーションの場合、すぐにスレッドプールを使い果たすと、リクエストが蓄積され始め、スレッドが利用可能になるのを待ちます。その理由だけでも、あなたが間違った道を進んでいる可能性があることを認識すべきです-そのような設計を検討している場合.
より良い解決策は、stage非同期に処理されるデータ(キュー、またはその他のタイプの一時/ステージングデータストア)で応答を返すことです。外部の独立したアプリケーション、または(Webコンテナーの外部にデプロイされた)その複数のインスタンスで、ステージングエンドポイントをポーリングし、バックグラウンドでデータを処理します。場合によっては、有限数の同時スレッドを使用します。このようなソリューションは、非同期/同時処理の利点を提供するだけでなく、必要な数のこのようなポーラーのインスタンスを実行でき、ステージングエンドポイントをポイントして分散できるため、スケーリングも可能になります。 HTH
厳密に言えば、Java EE仕様に従ってスレッドを生成することは許可されていません。一度。
ミドルウェアソリューションは、間違いなく、より堅牢で標準に準拠しています。
Spring 3以降、@ Asyncアノテーションを使用できます。
@Service
public class smg {
...
@Async
public getCounter() {...}
}
<context:component-scan base-package="ch/test/mytest">
および<task:annotation-driven/>
コンテキストファイル内
このチュートリアルを参照してください: http://spring.io/blog/2010/01/05/task-scheduling-simplifications-in-spring-3-0/
Tomcat7でうまく機能し、スレッドプールを管理する必要はありません。