- PR -

サーブレット、排他制御、マルチスレッドの考慮すべき点

投稿者投稿内容
うる
常連さん
会議室デビュー日: 2005/10/16
投稿数: 41
投稿日時: 2005-11-28 21:35
サーブレットで複数のユーザーからリクエストがあった場合、
Staticなプロバティを定義していないクラスであれば、
排他制御は考えなくてもいいのかなと思っております。
(DB等へのアクセスは行わないクラスにおいての話ですが)

ArrayListやHashMapを使う場合は、排他制御を行う必要があると書いてあったのですが、これらのクラスはStaticなプロバティがあるから排他制御を行う必要があるという事なのでしょうか?

また、排他制御を行わなければいけないクラスなのかどうかを知る方法があるのでしたら教えて頂きたいです。
排他制御を行う必要があるのに行っていなかったというのが恐いです。

それともサーブレットは全て排他制御にするべきものなのでしょうか?

質問ばかりですいません。。。
山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2005-11-28 21:42
最初の質問に対する回答だけ・・・。
SingleThreadModel(Servlet2.4でdeprecatedです)なサーブレットでなければサーブレットのインスタンスは通常一つしか作られません。同じサーブレットのインスタンスが複数のスレッドかアクセスされますので static な変数でなくても、競合状態が発生します。
うる
常連さん
会議室デビュー日: 2005/10/16
投稿数: 41
投稿日時: 2005-11-28 22:31
public class Test extends HttpServlet implements Runnable{
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException{

Thread th = new Thread(this);

res.setContentType("text/html; charset=iso-2022-jp");
PrintWriter out = res.getWriter();

out.println("<html>");
out.println("<head>");
out.println("<title>テスト</title>");
out.println("</head>");
out.println("<body>");

req.setCharacterEncoding("JISAutoDetect");

int i;
int j;
Test3 test3 = new Test3();

for(i=0;i<20;i++){
test3.addTestCnt();
j = test3.getTestCnt();

out.println(Integer.toString(j));
res.flushBuffer();
try
{
th.sleep(500);
}catch(InterruptedException e){}
}
}
}


class static Test3 {
private int testCnt=0;

int getTestCnt(){
return testCnt;
}

void addTestCnt(){
testCnt++;
}
}
------------------------------------------------
このようなテストプログラムを作って、
ブラウザを2つ立ち上げて実行してみたのですが、
private int testCnt=0;
この部分をstaticにすると、
ひとつの変数に対して、2つのブラウザから処理されているような感じになったのですが、
staticを外すと、別々の変数に対して処理を行っているような感じとなりました。

staticを付けた場合
ブラウザ1 1 3 5 7 ...
ブラウザ2 2 4 6 8 ...

staticを付け無い場合
ブラウザ1 1 2 3 4 ...
ブラウザ2 1 2 3 4 ...

このような感じだったので、staticを使わなければ競合は起きないのかなと思ったのですが。
インギさんの書かれている内容をもう少し詳しく教えて頂けませんでしょうか。
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2005-11-28 23:11
漠然と排他制御の必要性を気になさる前に、ご自身がサーブレットコンテナ
のマルチスレッド動作の仕組みをご理解されるのが先かとおもいますよ。

そのソースコードでは、
>implements Runnable
>Thread th = new Thread(this);
あたりは何の意味もないですよ。
うる
常連さん
会議室デビュー日: 2005/10/16
投稿数: 41
投稿日時: 2005-11-28 23:37
シュンさんへ

2つのブラウザを使ったテストなので、
ゆっくり動作させる為に、
th.sleep(500);
を使いたいが為の記述だったのですが、
意味なかったのでしょうか?
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2005-11-28 23:59
引用:
ArrayListやHashMapを使う場合は、排他制御を行う必要があると書いてあったのですが、これらのクラスはStaticなプロバティがあるから排他制御を行う必要があるという事なのでしょうか?


staticであるかは関係ありません。staticな変数を扱うコードの
多くでは必然的に排他制御も行う必要が出てくるというだけな話です。
同じクラスのインスタンスだとしても、何もしなくてもよい場合もあれば、
排他制御が必須となる場合もあります。一言では簡単に説明できないです。

Requestの処理中にnewして、ServletContext(Application Scope)などに
格納しないオブジェクトであれば、ほぼ排他制御は不要と言えるでしょう。

まずは、
なぜ排他制御をしないといけないのか?
クリティカルセクションの保護とは何か?
というところから調べてみてはいかがでしょうか。

スレッドについていろいろと誤解されてるようですし。
Lichtenstein
ベテラン
会議室デビュー日: 2003/11/06
投稿数: 61
投稿日時: 2005-11-29 09:10
Javaのクラスライブラリを使用するでしょうから、○○だから排他はいらない、という
考え方は危険です。

DeveloperWorksの記事がいい感じです。排他・マルチスレッドに関する記事を
探して読んでみることをお勧めします。
うる
常連さん
会議室デビュー日: 2005/10/16
投稿数: 41
投稿日時: 2005-12-01 21:00
http://www-06.ibm.com/jp/developerworks/java/040409/j_j-jtp09263.html
ここのページの内容で、

Vectorの要素を繰り返す以下のコードを考えてみてください。Vectorのすべてのメソッドは同期化されていますが、追加同期のないマルチスレッド環境でこのコードを使用するのはまだ安全とは言えません。他のスレッドが、ちょうど悪いタイミングで要素を削除してしまうと、get()がArrayIndexOutOfBoundsExceptionをスローすることになってしまうからです。
Vector v = new Vector();

// contains race conditions -- may require external synchronization
for (int i=0; i<v.size(); i++) {
doSomething(v.get(i));
}

「他のスレッドが、ちょうど悪いタイミングで要素を削除してしまうと」
この意味というのは、for文のi<v.size()が判断された後に、
Vectorの要素が削除され、v.size()が小さくなった後に、
doSomething(v.get(i)); が実行されてしまう事によって、
例外が発生するという意味なのでしょうか?

スレッドAとスレッドBがあった場合、
Vector v = new Vector();  で生成されたインスタンス変数vは、
スレッドAとスレッドB共通で使用されてしまうのでしょうか?
もしそうだったら全て同期を取らないと恐くて何も出来ない感じがしますが。

スキルアップ/キャリアアップ(JOB@IT)