電子書籍の厳選無料作品が豊富!

早速ではございますが、質問をさせていただきます。
以下のコード中のMonitorクラスを複数のスレッドが
共有して自由に入り込んでいるにも関わらす、
排他制御をしていないのにBROKENと表示されません。
final class Main
{
private final static int NUM = 10;
public static void main(String[] args)
{
Monitor m = new Monitor();
UserThread[] ut = new UserThread[NUM];
Thread[] t = new Thread[NUM];

for(int i=0;i<NUM;i++)
{
ut[i] = new UserThread(m);
t[i] = new Thread(ut[i]);
t[i].start();
}
}
}
final class UserThread implements Runnable
{
private final Monitor m;

public UserThread(Monitor m) { this.m = m; }

public void run()
{
System.out.println
(Thread.currentThread().getName()+" BEGIN");
while(true)
{
this.m.func();
}
}
}
final class Monitor
{
public void func()
{
int i1 = 0;
int i2 = 0;

i1++;
i2++;

if(i1 != i2)
{
System.out.println
("***** BROKEN ***** " +i1+"と"+i2);
}
}
}
動作確認を2日間くらい行っているのですが、それでも
BROKENと表示してくれません。javaの処理系によって
振る舞いがことなるかもしれませんので一概には言えませ
んが、いったいなぜBROKENと表示しないのでしょうか?
どうかご教授のほどよろしくお願いします。

A 回答 (9件)

CPUが複数あるコンピュータの場合は本当に複数のスレッドが本当に同時に動く場合があると思いますが、それでもローカル変数はメモリの中の違う所に入っているので絶対に取り違えることはありません。

(あるとしたらそれは Java VM か OS のバグです)。
    • good
    • 0

> Thread-0が実行中のとき、Thread-1も実行中となるようなことが起きたとしても、Thread-0の処理自体にThread-1がその処理に入り込むことはないということでよろしいのでしょうか?



「入り込む」という言葉をどういう意味で使っているのか分からないので何とも……。


って言うか皆さん、コードの意味を定める言語レベルの話と実行時のメモリがどうとかいう VM レベルの話を一緒にするのはよろしくないと思いますが。
    • good
    • 0

実際の動作で if の演算処理中に割り込みが掛かって他のスレッドに処理が移ることはあると思いますが、それでも問題なくスレッド毎に正常に動くようになっています。

なぜそれが出来るのかというと、 i1, i2 などの変数がメモリ上のどこにあるのかという情報がスレッド単位でまとめて保存してあり、割り込みにより処理が切り替わる時にその情報を適切に適用しているためです。そのため他のスレッドのローカル変数へのアクセスは起こりません。

この回答への補足

___noboru___様へ
大変勉強になりました。誠にありがとうございました。
マルチスレッドの基本的で根本的なことをご質問させてい
ただきたいのですが、
Thread-0が実行中のとき、Thread-1も実行中となるような
ことが起きたとしても、Thread-0の処理自体にThread-1
がその処理に入り込むことはないということでよろしい
のでしょうか?

補足日時:2006/03/03 21:00
    • good
    • 0

Monitor#func() の最初のところはこうなってますが、



public void func()
{
int i1 = 0;
int i2 = 0;

この int i1 = 0; の所の処理は新たに int の変数のための領域を確保して 0 に初期化して以後のアクセスは i1 という名前で行う、です。(i2 も同様です)。

で、この処理が各スレッドごとに実行されます。つまりスレッドごとに i1, i2 のメモリの領域が違っています。違っているから他のスレッドに影響することはないんです。

この回答への補足

___noboru__様へ。
ご教授ありがとうございました。大変勉強になりました。
ローカル変数は、各スレッド毎に保持されていて、各スレ
ッドごとに保持されているローカル変数の値は異なるのですね。実はローカル変数にアクセスする複数のスレッド
の振る舞いについてもわからなかったのですが、その他に
わからなかったことがありまして質問させていただきたいのですが、「1つのスレッドの処理に他のスレッドがその処理に割り込んで実行されるのではないか」ということが
あり得るのかどうかがわかりません。例えば、Thread-0が
Monitorクラスのif文の( )内を実行中にThread-0がi1に値を代入してi2にThread-1が割り込んできて値を代入
するようなことが起きるのかどうかがわかりません。
どうかご教授のほどよろしくお願い申し上げます。

補足日時:2006/03/03 19:17
    • good
    • 0

>フィールドはメインメモリに格納されていて、


>各スレッドはメインメモリを共有していると思うのですが

こんな話はきいたことがありませんが、どこの情報でしょうか?
スレッドは個別にメモリを割り当てられ、共有はしません。

インスタンス変数と、メソッド変数を混同されてないでしょうか?

この回答への補足

DQ9様へ
返事が遅れまして申し訳ありませんでした。
著者名はわからないのですが、その参考書には、確か
「メインメモリは、インスタンスが存在する領域であり、
インスタンスが持っているフィールドはメインメモリにあります。個々のスレッドが持っている作業用のメモリを
ワーキングメモリといい、ワーキングメモリには、メインメモリのうち必要な部分のコピー(例えばフィールドの値のコピー)が存在します。メソッドの引数やメソッド変数は1つのスレッドからしかアクセスされないので、ワーキングメモリ上にあると思ったほうが理解しやすい。」みたいなことが書かれていたことを読んだことがあります。

補足日時:2006/03/03 18:36
    • good
    • 0

言葉だけで説明するのはすごく難しいんですが、


簡単に説明すると、メソッドの中は例えスレッドでも同期がとられています。
というか、別のプログラムが中に割り込むことができません。

スタックとか、メモリ領域のことが理解できていれば分かるのですが。

この回答への補足

DQ9様へ。

たびたび申し訳ありません。フィールドはメインメモリ
に格納されていて、各スレッドはメインメモリを共有して
いると思うのですが、メソッド変数は各スレッドに
割り当てられているメモリ領域に格納されていると、どこ
かで聞いたことがあります。そのことと何か関連があるの
でしょうか?

補足日時:2006/03/02 23:11
    • good
    • 0

ちょっと横やりですが簡単に。


インスタンスメソッド内のローカル変数は、インスタンスの数だけ用意されます。

なので「複数のスレッドで共有」ということにはならないのです。
    • good
    • 0

変数のスコープについてちゃんと理解されていないようです。


スコープは基本中の基本ですので参考書を読み直すなりしてちゃんと理解した方が良いでしょう。

この回答への補足

Bonjin様のご指摘の通りおかしなコードをさらしてしまい
ました。申し訳ございませんでした。おかしなコードの部
分を修正して改めて質問をさせていただきます。
変更箇所はUserThreadクラスのrunメソッド内で無限ルー
プを削除したところと、Monitorクラスに無限ループを
入れたところです。以下のコードが修正したコードです。
final class UserThread implements Runnable
{
private final Monitor m;

public UserThread(Monitor m) { this.m = m; }

public void run()
{
System.out.println
(Thread.currentThread().getName()+" BEGIN");
this.m.func();
}
}

final class Monitor
{
public void func()
{
int i1 = 0;
int i2 = 0;

while(true)
{
i1++;
i2++;

if(i1 != i2)
{
System.out.println
("***** BROKEN ***** " +i1+"と"+i2);
}
}
}
}
何を質問したいのかというと、Monitorクラスの無限ループ
内で複数のスレッドがif文を実行するときにif文の( )
内に複数のスレッドが入り込んでもBROKENと表示されない
のはなぜなのかがわかりません。ローカル変数は、
複数のスレッドで共有するものではなく、各スレッドで
保持しているものであると認識しています。ですが、
if文の( )内に複数のスレッドが入り込むとBROKENと表示さ
れそうな気がしてなりません。BROKENと表示されないのは
なぜなのでしょうか?どうかご教授のほどよろしくお願い
申し上げます。

補足日時:2006/03/02 22:31
    • good
    • 0

何億回実行しても、「BROKEN」とは表示されませんよ。


Monitor#func()のi1もi2もメソッド変数なので競合することはありません。
これをインスタンス変数として、メソッドの外に宣言すればなるでしょう。

この回答への補足

DQ9様へ
「Monitor#func()のi1もi2もメソッド変数なので競合することはありません。」というのは、メソッド変数という
ものは、複数のスレッドで共有されるものではなくて、
たとえMonitorクラスのif文の( )内に複数のスレッド
が自由に入り込んでいたとしても、各スレッドは自分が持
っているメソッド変数i1とi2によってif文の評価を行うという認識でよろしいのでしょうか?

補足日時:2006/03/02 20:41
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!