• ベストアンサー

ローカル変数にアクセスする複数のスレッドの振る舞いについて

早速ではございますが、質問をさせていただきます。 以下のコード中の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と表示しないのでしょうか? どうかご教授のほどよろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.9

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

その他の回答 (8)

  • UKY
  • ベストアンサー率50% (604/1207)
回答No.8

> Thread-0が実行中のとき、Thread-1も実行中となるようなことが起きたとしても、Thread-0の処理自体にThread-1がその処理に入り込むことはないということでよろしいのでしょうか? 「入り込む」という言葉をどういう意味で使っているのか分からないので何とも……。 って言うか皆さん、コードの意味を定める言語レベルの話と実行時のメモリがどうとかいう VM レベルの話を一緒にするのはよろしくないと思いますが。

回答No.7

実際の動作で if の演算処理中に割り込みが掛かって他のスレッドに処理が移ることはあると思いますが、それでも問題なくスレッド毎に正常に動くようになっています。なぜそれが出来るのかというと、 i1, i2 などの変数がメモリ上のどこにあるのかという情報がスレッド単位でまとめて保存してあり、割り込みにより処理が切り替わる時にその情報を適切に適用しているためです。そのため他のスレッドのローカル変数へのアクセスは起こりません。

takeshix100
質問者

補足

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

回答No.6

Monitor#func() の最初のところはこうなってますが、 public void func() { int i1 = 0; int i2 = 0; この int i1 = 0; の所の処理は新たに int の変数のための領域を確保して 0 に初期化して以後のアクセスは i1 という名前で行う、です。(i2 も同様です)。 で、この処理が各スレッドごとに実行されます。つまりスレッドごとに i1, i2 のメモリの領域が違っています。違っているから他のスレッドに影響することはないんです。

takeshix100
質問者

補足

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

noname#18558
noname#18558
回答No.5

>フィールドはメインメモリに格納されていて、 >各スレッドはメインメモリを共有していると思うのですが こんな話はきいたことがありませんが、どこの情報でしょうか? スレッドは個別にメモリを割り当てられ、共有はしません。 インスタンス変数と、メソッド変数を混同されてないでしょうか?

takeshix100
質問者

補足

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

noname#18558
noname#18558
回答No.4

言葉だけで説明するのはすごく難しいんですが、 簡単に説明すると、メソッドの中は例えスレッドでも同期がとられています。 というか、別のプログラムが中に割り込むことができません。 スタックとか、メモリ領域のことが理解できていれば分かるのですが。

takeshix100
質問者

補足

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

回答No.3

ちょっと横やりですが簡単に。 インスタンスメソッド内のローカル変数は、インスタンスの数だけ用意されます。 なので「複数のスレッドで共有」ということにはならないのです。

  • Bonjin
  • ベストアンサー率43% (418/971)
回答No.2

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

takeshix100
質問者

補足

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と表示されないのは なぜなのでしょうか?どうかご教授のほどよろしくお願い 申し上げます。

noname#18558
noname#18558
回答No.1

何億回実行しても、「BROKEN」とは表示されませんよ。 Monitor#func()のi1もi2もメソッド変数なので競合することはありません。 これをインスタンス変数として、メソッドの外に宣言すればなるでしょう。

takeshix100
質問者

補足

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

専門家に質問してみよう