6

サーブレット仕様では、コンテナーが my の単一インスタンスをインスタンス化し、複数のワーカー スレッドからサービス メソッド ( / )java.servlet.HttpServletを呼び出すことが規定されています。doGet()doPost()

通常のスレッド化ルールによれば、誰かが何らかの時点で同期を手配しない限り、 init(ServeltConfig)'happen before' のインスタンス レベル フィールドへの割り当てが、 を実行している他のスレッドによって同じフィールドから読み取られることは保証されません。doGet()

おそらく、コンテナは実際にはある種の外部同期を行って、実行された作業init()が「後続の」スレッドに見えるようにします。

しかし、サーブレットの仕様は、私がスレッドセーフであることを明示的に保証していますか? 現時点ではそのような保証を見つけることができませんでしたが、認めざるを得ませんが、サーブレット 2.4 以降、仕様を端から端まで読んでいません。

編集

たとえば、一部の回答者が混乱しているため、私の質問は次のとおりです。次のクラスがスレッドセーフであると言うサーブレット仕様についてはどうですか?

@WebServlet (initParams = {@WebInitParam(name="b", value="true")})
public Decider extends HttpServlet {

    private boolean b = false;

    public void init(ServletConfig config) {
        this.b = Boolean.parseBoolean(config.getAttribute("b"));
    }

    public void doGet(HttpServletRequest req, HttpServletResponse res) {
        res.sendRedirect(b ? "/true" ? "/false");
    }

}

確かに、もし私がするなら:

public static void main(String[] argv) {

      HttpServlet s = new Decider();

      Thread t1 = new Thread(new Runnable() {
        public void run() {
            s.init(...);
        }
      });

      Thread t2 = new Thread(new Runnable() {
        public void run() {
            s.doGet(...);
        }
      });

      t1.start();
      t2.start();
}

...その後、スレッドのバグが発生します。コンテナーが必然的に異なる理由は何ですか?

編集2

「コンテナがそれを処理する」と主張するすべての回答は確かに歓迎されますが、私の質問は、サーブレット仕様がその動作を保証するかどうかについてです。この質問に適切に答えるには、サーブレットの仕様を参照する必要があります。(どのバージョンでも、私はクールです)。

4

2 に答える 2

7

これはinit javadocで明示的に述べられています:

サーブレット コンテナーは、サーブレットをインスタンス化した後、init メソッドを 1 回だけ呼び出します。サーブレットが要求を受け取る前に、init メソッドが正常に完了する必要があります。

また、サーブレットのライフサイクルに従うと、複数のスレッドからのリクエストのinit前にサーブレットを使用する必要があることが示されています。service

于 2013-10-03T11:36:34.883 に答える
2

...その後、スレッドのバグが発生します。コンテナーが必然的に異なる理由は何ですか?

あなたの例では、 メソッドinit()doGet()メソッドが重複する可能性があります。Servletこれはコンテナでは不可能です。コンテナはinit()、リクエストの処理を開始する前に、すべての呼び出しとその他の初期化を慎重に行います。これらのメソッドの境界を越えたマルチスレッドの問題はありません。

メソッドで使用されている共有日付にはまだ問題がありdoXXX()ます。

各コンテナーのソース コードを確認する以外に、 (および)のjavadocを確認することをお勧めします。ServletFilter

このインターフェースは、サーブレットを初期化し、リクエストを処理し、サーバーからサーブレットを削除するメソッドを定義します。これらはライフサイクル メソッドと呼ばれ、次の順序で呼び出されます。

  • サーブレットが構築され、次に init メソッドで初期化されます。
  • クライアントからサービス メソッドへのすべての呼び出しが処理されます。
  • サーブレットはサービスを停止され、destroy メソッドで破棄され、ガベージ コレクションが実行されてファイナライズされます。

仕様を真にサポートするServletには、コンテナはこれらのルールに従う必要があります。

これについては、サーブレット 3.0 仕様書Servlet Life Cycle の 2.3 章で説明されています。

サーブレット オブジェクトがインスタンス化された後、コンテナーは、クライアントからの要求を処理する前にサーブレットを初期化する必要があります。 サーブレットが永続的な構成データを読み取ったり、コストのかかるリソース (JDBC™ API ベースの接続など) を初期化したり、その他の 1 回限りのアクティビティを実行したりできるように、初期化が提供されます。コンテナーはinit、ServletConfig インターフェイスを実装する一意の (サーブレット宣言ごとに) オブジェクトを使用して Servlet インターフェイスのメソッドを呼び出すことにより、サーブレット インスタンスを初期化します。

太字は重要な部分。

于 2013-10-03T12:48:57.237 に答える