1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

セッション管理とスレッドモデル(JavaServlet/JSP編)

Last updated at Posted at 2020-12-18

セッション管理とスレッドモデル(JavaServlet/JSP編)

結論

JavaServletの場合、セッション内部でもマルチスレッド処理(平行処理)されているので、sessionオブジェクトへのアクセスは排他制御しないとダメかもしれない。

実験

親のjspでセッションを作成、その後、ko0.jspとko1.jspに対して同時にアクセスされるはずなので、その様子を見てみよう。

oya.jsp
<%@ page session="true" %>
<html>
<head>
</head>
<body>
Hello<br>
SessionId id <%= session.getId() %><br>
<iframe src="ko0.jsp"></iframe><br><hr>
<iframe src="ko1.jsp"></iframe>
</body>
</html>

ko0.jspとko1.jspは同じ内容で、10秒間スリープするだけの処理

ko0.jsp
<%= "Hello<br>\n" %>
<%
 java.util.Date date1 = new java.util.Date();
 out.println("SessionID id " + session.getId() + "<br>\n");
 out.println("Start is " + date1 + "<br>\n");
 java.lang.Thread.sleep(10000);
 java.util.Date date2 = new java.util.Date();
 out.println("  End is " + date2 + "<br>\n");
%>

結果

03.jpg

ko0.jsp と ko1.jsp が同時処理されているのがわかる。

つまり・・・

sessionオブジェクトへのアクセスには排他制御しておいた方がいいかもしれない

ということで・・・

Session変数が複数スレッドでブッ壊れるようなコードでテストしてみる

oya0.jsp
<%@ page session="true" %>
<html>
<head>
</head>
<body>
Hello<br>
SessionId id <%= session.getId() %><br>
<table border="1">
 <tr>
  <td><iframe src="ko0a.jsp" height="500"></iframe></td>
  <td><iframe src="ko1a.jsp" height="500"></iframe></td>
 </tr>
</table>
</body>
</html>

ko0a.jspは +1 ずつ計算結果をセッション変数に格納するよ
最後に結果を出力して、10秒後に再度結果を出力するよ

ko0a.jsp
<%= "Hello<br>\n" %>
<%
 java.util.Date date1 = new java.util.Date();
 out.println("SessionID id " + session.getId() + "<br>\n");
 out.println("Start is " + date1 + "<br>\n");
 int sum = 0;
 for(int i=0;i<100;i++){
  Integer sumI = (Integer)session.getAttribute("sum");
  if(sumI == null){
   sumI = 0;
  }
  sum = (int)sumI;
  sum++;
  session.setAttribute("sum", sum);
  out.print(i);
  out.print(" : ");
  out.print(sum);  
  out.println("<br>");
 }
 int sum0 = (int)session.getAttribute("sum");
 out.print("sum=");
 out.print(sum0);
 out.println("<br>");
 java.lang.Thread.sleep(10000);
 int sum1 = (int)session.getAttribute("sum");
 out.print("sum=");
 out.println(sum1);
 out.println("<br>");
 java.util.Date date2 = new java.util.Date();
 out.println("  End is " + date2 + "<br>\n");
%>

ko1a.jspは -1 ずつ計算結果をセッション変数に格納するよ
最後に結果を出力して、10秒後に再度結果を出力するよ

ko0a.jsp
<%= "Hello<br>\n" %>
<%
 java.util.Date date1 = new java.util.Date();
 out.println("SessionID id " + session.getId() + "<br>\n");
 out.println("Start is " + date1 + "<br>\n");
 int sum = 0;
 for(int i=0;i<100;i++){
  Integer sumI = (Integer)session.getAttribute("sum");
  if(sumI == null){
   sumI = 0;
  }
  sum = (int)sumI;
  sum--;
  session.setAttribute("sum", sum);
  out.print(i);
  out.print(" : ");
  out.print(sum);  
  out.println("<br>");
 }
 int sum0 = (int)session.getAttribute("sum");
 out.print("sum=");
 out.print(sum0);
 out.println("<br>");
 java.lang.Thread.sleep(10000);
 int sum1 = (int)session.getAttribute("sum");
 out.print("sum=");
 out.println(sum1);
 out.println("<br>");
 java.util.Date date2 = new java.util.Date();
 out.println("  End is " + date2 + "<br>\n");
%>

ということで・・・結果

05.jpg

うーん、forブロック内部では排他制御している!?

06.jpg

左側の

  • sum=100
  • sum=0

という2行を見ると、左側(ko0a.jsp[sum++])の1⇒100を(ロックしつつ)実行後に、右側(ko1a.jsp[sum--])の100⇒0を実行したような感じに見える

ということで・・・パート2

Session変数が複数スレッドでブッ壊れるようなコードでテストしてみる Part2

oya1.jsp
<html>
<head>
</head>
<body>
Hello<br>
SessionId id <%= session.getId() %><br>
<table border="1">
 <tr>
  <td><iframe src="ko0b.jsp" height="500"></iframe></td>
  <td><iframe src="ko1b.jsp" height="500"></iframe></td>
 </tr>
</table>
</body>
</html>
ko0b.jsp
<%= "Hello<br>\n" %>
<%
 java.util.Date date1 = new java.util.Date();
 out.println("SessionID id " + session.getId() + "<br>\n");
 out.println("Start is " + date1 + "<br>\n");
 int sum = 0;
 for(int i=0;i<50;i++){
  Integer sumI = (Integer)session.getAttribute("sum");
  if(sumI == null){
   sumI = 0;
  }
  sum = (int)sumI;
  sum++;
  session.setAttribute("sum", sum);
  out.print(i);
  out.print(" : ");
  out.print(sum);  
  out.println("<br>");
  java.lang.Thread.sleep(1000);
 }
 int sum0 = (int)session.getAttribute("sum");
 out.print("sum=");
 out.print(sum0);
 out.println("<br>");
 java.lang.Thread.sleep(10000);
 int sum1 = (int)session.getAttribute("sum");
 out.print("sum=");
 out.println(sum1);
 out.println("<br>");
 java.util.Date date2 = new java.util.Date();
 out.println("  End is " + date2 + "<br>\n");
%>

ko0b.jspは +1 ずつ計算結果をセッション変数に格納するよ
最後に結果を出力して、10秒後に再度結果を出力するよ

Part1との違いは

  • forブロックの中に1秒間のsleepを入れたこと。
  • 100回は多いので、50回に減らした。
ko1b.jsp
<%= "Hello<br>\n" %>
<%
 java.util.Date date1 = new java.util.Date();
 out.println("SessionID id " + session.getId() + "<br>\n");
 out.println("Start is " + date1 + "<br>\n");
 int sum = 0;
 for(int i=0;i<50;i++){
  Integer sumI = (Integer)session.getAttribute("sum");
  if(sumI == null){
   sumI = 0;
  }
  sum = (int)sumI;
  sum--;
  session.setAttribute("sum", sum);
  out.print(i);
  out.print(" : ");
  out.print(sum);  
  out.println("<br>");
  java.lang.Thread.sleep(1000);
 }
 int sum0 = (int)session.getAttribute("sum");
 out.print("sum=");
 out.print(sum0);
 out.println("<br>");
 java.lang.Thread.sleep(10000);
 int sum1 = (int)session.getAttribute("sum");
 out.print("sum=");
 out.println(sum1);
 out.println("<br>");
 java.util.Date date2 = new java.util.Date();
 out.println("  End is " + date2 + "<br>\n");
%>

ko1b.jspは -1 ずつ計算結果をセッション変数に格納するよ
最後に結果を出力して、10秒後に再度結果を出力するよ

ということで・・・結果 パート2

排他していないので、値がめちゃくちゃになった・・・・ヨシ

07.jpg

フレームの下はこんな感じ

08.jpg

Session変数は、マルチスレッドからの排他制御をきちんと実装した方がいいかもしれない。

結論

セッション変数の処理には、排他制御については少しは気を付けたほうがいいぞ。

でも、session変数のためだけに、synchronized しちゃうと、全体をロックしてしまうので!? 実行効率が落ちてしまうような気がする。

HTTPセッションの内部だけを同期させる方法って、あるのかな!? (誰か教えて)

戻る

セッション管理とスレッドモデル

以上

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?