HttpSessionスレッドセーフですか、属性を設定/取得するスレッドセーフオペレーションですか?
-
03-07-2019 - |
質問
また、セッションに保存されているオブジェクトの状態がわかっていることを確認するために、設定されるオブジェクトはスレッドセーフである必要があります。
また、私はウェブ上で読んでいる人が次のように使用することを提案しています:
synchronized(session) {
session.setAttribute("abc", "abc");
}
これは有効な提案ですか?
解決
いいえ、IBMによるとスレッドセーフではありません- Javaの理論と実践:ステートフルWebアプリケーションはすべて壊れていますか?。同期する必要があります。
HttpSessionがスレッドセーフではない方法 Java Ranchからも役立ちます。
他のヒント
サーブレット2.5仕様:
リクエストを実行する複数のサーブレット スレッドは、 同時に同じセッションオブジェクト。 コンテナは、 内部データの操作 セッションを表す構造 属性は スレッドセーフな方法。開発者は スレッドセーフの責任 属性オブジェクトへのアクセス 自分自身。これにより、 内部の属性コレクション コンカレントからのHttpSessionオブジェクト アクセス、機会の排除 アプリケーションがそれを引き起こすために 破損するコレクション。
これは安全です:
// guaranteed by the spec to be safe
request.getSession().setAttribute("foo", 1);
これは安全ではありません:安全です:
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);
これは安全であるとは保証されていません:
// 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の書籍を含む)が、Servlet仕様で機能することは保証されていません。 セッションIDを使用してミューテックスを作成できますしかし、より良いアプローチが必要です。
いいえ。また、同じクライアント(セッション)で同時リクエストを実行したくないので、これらのリクエストを AbstractController はSpring MVCで行います
いくつかの点で、これはクライアントの設計に依存します。
Webデザインで、1つのクライアントが同じHTTPセッションを使用して複数の未処理の同時リクエストを行う機会はありますか?単一のHTTPセッションを複数のソケットに結び付けない限り、これは難しいようです。 (別名、AJAX)これを行うと、特定のクライアントのHTTPアクセスはサーバーに関する限りシングルスレッドになります。つまり、単一のセッションは事実上スレッドセーフです。
セッションオブジェクトの同期により、Webアプリケーションが複数の同時リクエストを処理できるようになる将来の変更に対してアプリケーションが安全になります。これは悪い考えではありません。現代のJava実装では、特に同期が通常競合しない場合、同期に以前に関連付けられていた大きなコストはありません。アプリケーションがAJAXを使用している場合、Webサーバーへの複数の進行中の同時リクエストが予想されることを意味する場合、同期は必須です。
これらはそうではありませんが、ほとんどの場合、クライアントは単一のスレッドでのみそれらにアクセスします。
異なるクライアントには異なるスレッドがあり、それぞれに独自のセッションがあります。
Eddieが指摘しているように、同じセッションにアクセスする2つのスレッドに直面する可能性がある状況の1つは、2つのajax呼び出しが同じセッション属性を変更しようとしていることです。それ以外の場合、問題は発生しません。
セッションはスレッドセーフではなく、getメソッドもsetメソッドもスレッドセーフであるとは限りません。一般に、サーブレットコンテナでは、マルチスレッド環境にあると想定する必要があり、提供されているツールは安全ではありません。
これは、セッションに保存するオブジェクトにも当てはまります。セッション自体は保存されたオブジェクトを操作しませんが、別のスレッドでオブジェクトを取得して操作を試みることができます。競合状態が発生する可能性があるかどうかを確認するために、独自のコードを調べるのはあなた次第です。
投稿したコード例は有効ですが、問題は例の限られた範囲を超えて存在する可能性があります。セッションへの設定中に条件がないことを保証しますが、他のスレッドがセットをオーバーライドすることを妨げるものはありません。リクエスト内のコードが変更されていない値に依存している場合、まだ問題が発生している可能性があります。