web-dev-qa-db-ja.com

HttpSessionスレッドセーフ、属性の設定/取得スレッドセーフ操作はありますか?

また、セッションに保存されているオブジェクトの状態がわかっていることを確認するために、設定されるオブジェクトはスレッドセーフである必要があります。

また、私はいくつかを使用することを提案するウェブで読んでいた:

synchronized(session) {
  session.setAttribute("abc", "abc");
}

これは有効な提案ですか?

52
Berlin Brown

いいえ、IBMによれば、スレッドセーフではありません- Javaの理論と実践:すべてのステートフルWebアプリケーションが壊れていますか? 。同期する必要があります。

HttpSessionがスレッドセーフでない方法 from Java Ranchも役立つかもしれません。

36
duffymo

サーブレット2.5仕様:

要求スレッドを実行する複数のサーブレットは、同じセッションオブジェクトに同時にアクティブにアクセスできます。コンテナは、セッション属性を表す内部データ構造の操作がスレッドセーフな方法で実行されることを保証する必要があります。開発者には、属性オブジェクト自体へのスレッドセーフアクセスに対する責任があります。これにより、HttpSessionオブジェクト内の属性コレクションが同時アクセスから保護され、アプリケーションがそのコレクションを破損させる機会がなくなります。

これは安全です:

// guaranteed by the spec to be safe
request.getSession().setAttribute("foo", 1);

これはnot安全です:

HttpSession session = request.getSession();
Integer n = (Integer) session.getAttribute("foo");
// not thread safe
// another thread might be have got stale value between get and set
session.setAttribute("foo", (n == null) ? 1 : n + 1);

これはnot安全であることが保証されています:

// no guarantee that same instance will be returned,
// nor that session will lock on "this"
HttpSession session = request.getSession();
synchronized (session) {
  Integer n = (Integer) session.getAttribute("foo");
  session.setAttribute("foo", (n == null) ? 1 : n + 1);
}

私はこの最後のアプローチが提唱されているのを見ました(J2EEの書籍を含む)が、サーブレット仕様で機能することは保証されていません。 セッションIDを使用してミューテックスを作成する が可能ですが、より良いアプローチが必要です。

63
McDowell

いいえ。また、同じクライアント(セッションを含む)で同時リクエストを実行したくないので、Spring MVCで AbstractController のようにこれらのリクエストをシリアル化する必要があります。

4
cherouvim

いくつかの点で、これはクライアントの設計に依存します。

Webデザインで、単一のクライアントが同じHTTPセッションを使用して複数の未処理の同時要求を行う機会がありますか?単一のHTTPセッションを複数のソケットに結び付けない限り、これは難しいようです。 (別名、AJAX)これを行うと、特定のクライアントのHTTPアクセスはサーバーに関する限りシングルスレッドになります。つまり、単一のセッションは事実上スレッドセーフです。

セッションオブジェクトを同期すると、Webアプリケーションが複数の同時リクエストを処理できるようになる将来の変更に対してアプリケーションが安全になりますので、悪い考えではありません。現代のJavaの実装では、特に同期が通常競合しない場合、同期に以前に関連付けられていた大きなコストはありません。アプリケーションがAJAXを使用している場合、複数のイン同時リクエストをWebサーバーに送信する場合は、同期が必須です。

3
Eddie

そうではありませんが、ほとんどの場合、クライアントは単一のスレッドでのみそれらにアクセスします。

異なるクライアントは異なるスレッドを持ち、それぞれが独自のセッションを持ちます。

Eddieが指摘しているように、同じセッションにアクセスする2つのスレッドに直面する可能性がある状況の1つは、2つのajax呼び出しが同じセッション属性を変更しようとしていることです。それ以外の場合、問題は発生しません。

2
OscarRyz

セッションはスレッドセーフではなく、getメソッドもsetメソッドもスレッドセーフであるとは限りません。一般に、サーブレットコンテナでは、マルチスレッド環境にあると想定する必要があり、提供されているツールは安全ではありません。

これは、セッションに保存するオブジェクトにも当てはまります。セッション自体は保存されたオブジェクトを操作しませんが、別のスレッドでオブジェクトを取得して操作を試みることができます。独自のコードを調べて、競合状態が発生するかどうかを確認するのはユーザー次第です。

投稿したコード例は有効ですが、問題は例の限られた範囲を超えて存在する可能性があります。セッションへの設定中に条件がないことを保証しますが、他のスレッドがセットをオーバーライドすることを妨げるものは何もありません。リクエスト内のコードが変更されていない値に依存している場合は、依然として問題が発生する可能性があります。

1
DefLog