- PR -

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

投稿者投稿内容
うる
常連さん
会議室デビュー日: 2005/10/16
投稿数: 41
投稿日時: 2005-12-03 07:42
返答ありがとうございました。
「Java言語で学ぶデザインパターン入門 マルチスレッド編」
早速注文しました。
ちょっと高かったですが。
Kazuki
ぬし
会議室デビュー日: 2004/10/13
投稿数: 298
投稿日時: 2005-12-03 14:24
下のコードは,メンバ変数valueの値をローカル変数にコピーして1増やす。
そして,適当な時間スリープした後に,value + 1した結果がローカル変数の
値と等しいか比べてメッセージを出すコードです。
これを動かすと「駄目じゃん」っていうメッセージがボコボコ
出てくる。
コード:
public class ThTest implements Runnable {
	int value = 0;

	public void run() {
		while (true) {
			int i = value;
			i++;

			long sleepTime = (long) (Math.random() * 10) * 1000;
			try {
				Thread.sleep(sleepTime);
			} catch (InterruptedException e) {
			}

			if (i == value + 1) {
				System.out.println(Thread.currentThread().getName() + " : 予想通り");
				value = i;
			} else {
				System.out.println(Thread.currentThread().getName() + " : 駄目じゃん");
				value = 0;
			}
		}
	}

	public static void main(String[] args) {
		ThTest test = new ThTest();
		Thread th1 = new Thread(test);
		Thread th2 = new Thread(test);
		
		th1.start();
		th2.start();
		
	}

}


Servletも同じように,1つのインスタンスが複数のスレッドから参照されるので,
メンバ変数を使うなら,かなり気をつけないといけない。
(というか個人的には怖くて普通使えない)
うる
常連さん
会議室デビュー日: 2005/10/16
投稿数: 41
投稿日時: 2005-12-03 23:32
サーブレットでのマルチスレッドですが、
このような認識で良いのでしょうか?
この認識で合っていれば、すっきりするのですが。

-----------------------------------------
サーブレットの処理を行うクラス
public class Hoge extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException{
//サーブレット処理
}
}

-----------------------------------------
サーブレットコンテナ側での呼び出しイメージ
ブラウザ1とブラウザ2からアクセスがあった場合
req1,res1はブラウザ1に対応
req2,res2はブラウザ2に対応

Hoge hoge = new Hoge;
new ServletThread(hoge, req1, res1).start();
new ServletThread(hoge, req2, res2).start();

ServletThreadは適当な名前で作りました。
ServletThread内のrunメソッドで、
hoge.doGet(req, res);が実行される。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2005-12-04 01:38
>うるさん
大雑把に言えば、そんな感じで差し支えないと思います。

実際にはもっと複雑な手法で構成されていますが、
サーブレット利用者側からすると、
うるさんのスレッドに対する認識で充分だと思います。
うる
常連さん
会議室デビュー日: 2005/10/16
投稿数: 41
投稿日時: 2005-12-04 08:16
先ほどの自分の例で確認して頂きたいところがあるのですが、

コード:
public class Hoge extends HttpServlet { 
  public void doGet(HttpServletRequest req, HttpServletResponse res) 
                   throws IOException, ServletException{ 
    //サーブレット処理 
    int a;
    Hoge2 hoge2 = new Hoge2;
  } 
}



引数やメソッド内で宣言されているオート変数のint aは、
スレッド間で競合が起こらないと思うのですが、この認識で問題ありませんでしょうか。

newされたHoge2クラスも、Hoge2クラス内でstaticなプロパティが無ければ、スレッド間での競合は起こらないと思うのですが、この認識で良いのでしょうか?
スレッド内でnewされたクラスのインスタンスは別々に確保されるという認識です。
Kazuki
ぬし
会議室デビュー日: 2004/10/13
投稿数: 298
投稿日時: 2005-12-04 09:52
自分でスレッド起こして競合するような状況を作らない限り大丈夫です。
うる
常連さん
会議室デビュー日: 2005/10/16
投稿数: 41
投稿日時: 2005-12-04 12:26
Kazukiさん回答ありがとうございます。

それでも、ArrayList等を使う場合は、synchronizedListを使わないとだめなのですよね。
ArrayListがstaticなプロパティを使っているから同期を取らないとダメなのでしょうか?
そういう事なら納得できますが、それ以外の要因で同期を取らなくてはいけないのでしたら、まだどうも納得がでません。
スレッド内でnewされたクラスのインスタンスは別々に確保されるという考えが崩れてしまいます。

コード:
public class Hoge extends HttpServlet { 
  public void doGet(HttpServletRequest req, HttpServletResponse res) 
                   throws IOException, ServletException{ 
    //サーブレット処理 
    int a;
    Hoge2 hoge2 = new Hoge2;
    ArrayList arrayList = new ArrayList();
    List list = (List)Collections.synchronizedList(arrayList);  
  } 
}




あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2005-12-04 13:20
引用:

うるさんの書き込み (2005-12-04 12:26) より:
それでも、ArrayList等を使う場合は、synchronizedListを使わないとだめなのですよね。
ArrayListがstaticなプロパティを使っているから同期を取らないとダメなのでしょうか?



ArrayListは「クラス単位」ではスレッドセーフです。同一インスタンスを
複数スレッドで共有しない限り、明示的な同期化は必要ありません。
内部にstaticな変数があったとしても、うまく扱ってるはずです。

引用:

コード:
public class Hoge extends HttpServlet { 
  public void doGet(HttpServletRequest req, HttpServletResponse res) 
                   throws IOException, ServletException{ 
    //サーブレット処理 
    int a;
    Hoge2 hoge2 = new Hoge2;
    ArrayList arrayList = new ArrayList();
    List list = (List)Collections.synchronizedList(arrayList);  
  } 
}





このarrayListに代入されたインスタンスを他のスレッドと共有させたりせず、
リクエスト処理の完了時に破棄(ガベージコレクトの対象となる)される場合は
特に同期化を考える必要はないです。

Collections.synchronizedList()は、Vector等のメソッド宣言のsynchronized
だけでは不十分なのと同じ理由で不十分です。多くの場合は、自分で排他制御を
行わないと無意味なモニタの獲得が発生するだけでしょう。

私は、CollectionsのsynchronizedList()系のメソッドをVectorなどの旧仕様の
コレクションの同期化と互換性を持たせる目的でしかないと捉えています。

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