非同期サーブレットのベスト・プラクティス
非同期サーブレット・フィーチャーを使用すると、着信要求と応答を、要求を起こしたオリジナル・スレッドにバインドしなくても処理することができます。
非同期サーブレットを使用するときには、以下のベスト・プラクティスを検討してください。
- アプリケーションは、必要な非同期操作ごとに新規スレッドを作成すべきではありません。 アプリケーションは、スレッド・プールを使用するか、 または AsyncContext start(Runnable) メソッドを使用するだけで済みます。
- クライアント/ブラウザー・サイドでは、AJAX を使用して、ページの特定部分が非同期的に更新されるようにすることができます。
- サーブレット・コンテナーは、startAsync コマンドを開始した Web コンテナー・スレッドが存在しない場合に dispatch または complete に対する呼び出しが開始されないようにします。 ただし、サーブレット・コンテナーは、同じ要求と応答を同時に使用して複数のスレッドを処理することはありません。この場合、アプリケーションは自身の並行性または同期性の課題を処理することができますが、デッドロックまたは競合状態になる可能性があるので、推奨できません。ディスパッチ または完了メソッドが、ユーザー作成のスレッドまたは start(Runnable) を使用して開始された 実行可能対象から呼び出された場合は、 新規スレッドのディスパッチまたは完了が即時に開始される可能性があるため、 これらの呼び出しを開始したそのスレッドから要求または応答に それ以上の変更を加えることは危険です。 2 つのスレッドで要求と応答にアクセスすることができますが、両方のスレッドが これらのオブジェクトを変更すると、不確定な結果が引き出される可能性があります。 したがって、ディスパッチを呼び出した同じスレッドからのそのディスパッチの後では、要求または応答でメソッドを呼び出さないでください。完了操作が呼び出された後では、要求または応答でメソッドを呼び出さないでください。
- 非同期リスナーは、非同期操作の制限時間になると開始される、onTimeout メソッドを備えています。
しかし、あるスレッドで onTimeout が
実行されても、別のスレッドではまだ非同期操作を実行している場合があります。
このシナリオは、複数のスレッドが同じ要求および応答を誤って同時に使用する最も一般的なケースです。
AsyncListener と非同期操作の両方から以下のように共有 AtomicBoolean メソッドを使用すると、簡単にこのシナリオを解決できます。
この方法では、1 つのスレッドしか応答への書き込みアクセスを取得しません。AtomicBoolean isOkayToRun = (AtomicBoolean) request.getAttribute("isOkayToRun"); if (isOkayToRun.setAndGet(false)){ //do a dispatch }
- Web コンテナーは、タイムアウトになったときに、start(Runnable) メソッドに対する呼び出しによってキューに入れられたすべての runnable を取り消そうとします。 ただし、既に開始された実行可能対象を中断することはできません。 中断すると、メモリー・リークが発生するためです。
- タイムアウト通知を行うスレッドの数は、きわめて少数です。 クライアント接続が低速である場合、小さな書き込み操作でも時間がかかることがあるので、タイムアウトから集中型操作や書き込み操作を実行することは、推奨されません。非同期タイムアウトを使用不可にすると、OutOfMemory エラーが発生したり、TCP チャネル接続が使い尽くされたりする可能性が高くなります。デフォルトのタイムアウトは 30 秒です。
- 非同期サーブレット・オプション (タイムアウト設定や AsyncContext start(Runnable) メソッドなど) を 構成するには、管理コンソールで、 の 順でクリックします。 Web コンテナーの構成については、Web コンテナー設定に関するトピックを参照してください。
重要: 非同期要求ディスパッチャー (ARD) およびリモート要求ディスパッチャー (RRD) は、非同期サーブレットを使用している場合にはサポートされません。
ヒント: 非同期サーブレットのメトリックについては、Web アプリケーション・カウンターのトピックを参照してください。