スレッドの状態遷移について - synchronizedの部分について

このQ&Aのポイント
  • Javaの本において、スレッドの状態遷移について説明があります。
  • 特に、Synchronized指定されたメソッド(同期メソッド)の部分に注目しました。
  • 質問者は、スレッドがsleep()メソッドで『実行不可能状態』になった場合、他のスレッドも『実行不可能状態』へ移行するのかについて質問しています。
回答を見る
  • ベストアンサー

スレッドの状態遷移について。。。

Javaの本を買って読んでいます。 その中の「スレッド」のカテゴリーの「状態遷移」のところの「synchronized」の部分に、こう書かれています。 -------------------------- ・・・・・・ なお、sleepメソッドでスリープ状態(実行不可能状態)になったスレッドはロックを保持したまま開放しません。 そのため、ロックを取得できないで待たされるスレッドも実行不可能状態へ移行させられます。 -------------------------- これは、Synchronized指定されたメソッド(同期メソッド)の部分で出てきた文章でして、 私は、こう解釈しました。 → 例えば、同じオブジェクトの参照を引数とするスレッドが3つあり、その中の1つが『実行中』状態にある(仮に t1 とする)として(つまり残り2つ( t2 t3 )は『実行可能状態(プール)』にある。)、 実行中の t1 がsleep()メソッドで『実行不可能状態』になった場合、 『実行可能状態』にあった、t2 t3 も『実行不可能状態』へ移行する事になる。 間違っていますか? もし、この解釈が正しければ、こうなりますよね? t1・・・・・・・『実行中』 → 『実行不可能状態』 t2 t3・・・『実行可能状態』 → 『実行不可能状態』 ところが、状態遷移の5つの状態の図を見ると、 『実行可能状態』 から 『実行不可能状態』 へは、矢印→が書かれておりません。(逆向きの矢印がありますが。) どういう意味でしょうか。 java初心者ですが、 解りやすく教えて頂けると助かります。 宜しくお願い致します。

  • Java
  • 回答数3
  • ありがとう数1

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

  • ベストアンサー
  • tyatsumi
  • ベストアンサー率58% (30/51)
回答No.3

添付失敗してしもうた。。

その他の回答 (2)

  • tyatsumi
  • ベストアンサー率58% (30/51)
回答No.2

Wikipediaから図を持ってきて添付してみました。 Blocked: 実行不可能状態(ブロック、スリープ) Waiting: 実行可能状態(待機状態) Running: 実行中 と対応していると思います。 t1がm1の中でsleepが実行されると、 スレッドは実行を停止ます。 これが「実行不可能状態」に対応しているはずです。 sleepは指定時間の間何もしない(実行を停止)で、 指定時間が過ぎると実行を再開します。 この段階で「実行可能状態」に移り、「実行中」に移ります。 t1はまだm1の中なのでここまではロックを保持しているので、 他のスレッドt2などはまだm1に入れません。 この段階でt2がm1に入ろうとすればt2は実行不可能状態になります。 t1がm1を終了するとロックを外すので、 t2がm1に入れるようになります。 t2がm1の入口で待っていた(実行不可能状態)とすると、 このときt2は実行可能状態に移り、実行中に移ればm1に入ります。

参考URL:
http://ja.wikipedia.org/wiki/%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9
  • tyatsumi
  • ベストアンサー率58% (30/51)
回答No.1

簡単に言うと、synchronized宣言されたメソッドは、同時にひとつのスレッドでしか実行されません。 synchronized宣言されたメソッドm1があるスレッドt1で実行されている最中は、 他のスレッドt2はそのメソッドm1を実行しようとすると入ることができず待たされます。 t1がm1を終えるとt2は待ちを解除されm1に入ることができます。 ところがt1がm1を実行中にsleepしてしまうと、 sleepが終わるまでt1はm1を終了しないので、 m1に入ろうとしていたスレッドt2はずっと待たされます。 t1がsleepを終えてm1を抜けるまで待たされることになります。 という意味のはずです。 なお、スレッドt2はm1を実行しようとしたら待たされるのであって、 他の関係ない処理は継続して実行できます。 なのでt1が止まってしまったからt2も無条件に止まるということはありません。 ちなみに、ひとつのクラスC(のインスタンスi)内の2つのメソッドm1, m2がどちらもsynchronized宣言されていると、 あるスレッドt1がm1を実行中のとき、別なスレッドt2はm1に入れないだけでなく、m2にも入れません。 これはm1, m2はどちらも共通のオブジェクトiで排他処理(ロック)されているからです。 一方でスレッドt2はsynchronized宣言されていないC(i)内のメソッドm3には自由に入れます。 何のオブジェクトに関しても排他処理されていないからです。

yukiyayako
質問者

お礼

ご丁寧な文面、付随事項、解りやすい解説をありがとうございます。 ちょっと確認の意味もこめての質問させてください。 >ところがt1がm1を実行中にsleepしてしまうと、 >sleepが終わるまでt1はm1を終了しないので、・・・ そもそもsleepは『実行不可能状態』にいるわけですよね? という事は、t1がsleepを終了すると、『実行中』には戻れないから、 ロックだけを開放して『実行不可能状態』に待機しているという事ですか? で、t2かt3のどちらかがsynchronizedスレッドに入っていく、 という事でいいのでしょうか? つまり、t2もt3も『実行可能状態』に居続ける、という事でいいのでしょうか。 何度もすみません、宜しくお願い致します。

関連するQ&A

  • Javaスレッドの割り込みについて

    Javaのスレッド割り込み制御についてご質問です。 スレッドの割り込みの際に用いるメソッドinterrupt()は、 通常、対象のスレッドがsleep()やwait()状態の最中でアクセス不能な場合に使用しますが、 対象のスレッドが、sleep()やwait()以外の状態で、正常に動作している場合に interrupt()を実行した場合、どのような動きをするのでしょうか? 特に問題などありますでしょうか? お手数ですが、どなたかご教授願います。

  • wait中にinterruptを呼ばれたスレッドの振る舞いについて

    はじめまして。javaの初心者です。 どうしてもわからないことがあります。 例えば、以下のコードで、 class Foo { public synchronized void foo() { while(条件) { try { this.wait(); } catch(InterruptedException ex)    {     処理    } } } } wait中であったスレッドは、他のスレッドによって interrupt()メソッドを実行されたときは、Fooの ロックを取得してからcatch節を実行すると思うのですが、もし、以下のコードの場合は、 class Foo { public synchronized void foo() throws InterruptedException { while(条件) { this.wait(); } } } wait中であったスレッドは、他のスレッドによって interrupt()を実行されたときにすぐにInterrupted Exceptionをスローするのか、それとも Fooクラスのロックを取得してからInterruptedExceptionをスローするのかどちらなのか がわかりません。どうか教えてください。よろしく お願いします。

    • ベストアンサー
    • Java
  • 交互にスレッド実行 (どうしてちゃんと動いてる?)

    http://oshiete1.goo.ne.jp/qa2968378.html で質問した者です。 2つのスレッドで1と2を交互に実行する以下のプログラム。 final Object obj1 = new Object(); //スレッド間通信用のobject final Object obj2 = new Object(); //スレッド間通信用のobject2 Thread t1 = new Thread() {  public void run() {   try {    while(true) {     System.out.print("1");     synchronized (obj1) {      synchronized (obj2) {       obj2.notify();//相手をnotifyして      }      obj1.wait();//自分はwait     }    }   } catech (Exception e){} }; Thread t2 = new Thread() {  public void run() {   try {    while(true) {     System.out.print("2");     synchronized (obj2) {      synchronized (obj1) {       obj1.notify();      }      obj2.wait();     }    }   } catch (Exception e){}  } }; Thread t1 = new Test1(); Thread t2 = new Test2(); t1.start(); while(t1.getState() != Thread.State.WAITING); t2.start(); が思ったように動いてはいるものの、なぜ正常に動いているかがわかりません。 t1が wait() したときはobj1のロックをもっていて、t2の synchronized (obj1){obj1.notify()} ブロックに入れず待機するはずだと思うのですが。 なぜちゃんと動いているのでしょう?

    • ベストアンサー
    • Java
  • wait()したスレッドが起こされるタイミング

    以下のコードにおいて。 % java ThreadWaitTest 2 の場合はaと表示したまま止まりますが、 % java ThreadWaitTest 1 の場合はスレッドの終了に伴ってwait()が切れ、bまで表示します。 私の望む動作は前者です。 後者の場合、これはつまりスレッドをwaitした際の待機プールがスレッドオブジェクトの場合、そのスレッドの実行が終了すると待機プールにある待機スレッドを自動でnotify()してしまうことを意味していると思うのですが、この解釈はあっていますか? Java のAPIドキュメントに 「別のスレッドが notify メソッドまたは notifyAll メソッドを呼び出してこのオブジェクトのモニター上で待機するスレッドに通知を出すまで待機します」 とあるように、ユーザが明確的にnotifyしないと起こらないと思いこんでいました。 なぜこういう仕様になっているのでしょうか? また、この仕様について詳しく書いてあるサイトやドキュメントなどありませんでしょうか? public class ThreadWaitTest extends Thread {  public Object mutex = new Object();    public static void main(String[] args) {   try {    ThreadWaitTest test = new ThreadWaitTest();    test.start();    System.out.println("a");    switch (new Integer(args[0])) {    case 1:     synchronized(test) {      test.wait();     }     break;    case 2:     synchronized(test.mutex) {       test.mutex.wait();     }     break;    }    System.out.println("b");   } catch (InterruptedException ie) {    ie.printStackTrace();   }  }  public void run() {   try {    Thread.sleep(5000);   } catch (InterruptedException ie){    ie.printStackTrace();}   } }

    • ベストアンサー
    • Java
  • synchronized メソッド について

    http://www.stackasterisk.jp/tech/java/sjcp05_15.jsp ↑の問題の解答で ”あるスレッドが「9行目~11行目、15行目~19行目」までの処理を実行している間に、 「23行目~25行目」の処理を他のスレッドが実行することはありえるのです。” とあるのですが removeObj1メソッドとremoveObj2メソッドは synchronizedメソッドだと思うので removeObj1メソッドとremoveObj2メソッドが 同時に実行される事はないと思ったのですが synchronizedメソッドないにsynchronizedブロックが あるとブロック単位でのロックになるのでしょうか? addObj1が実行されているときに removeObj2が実行されるのはわかるのですが、 ”ArrayListのremove( )メソッドを呼ぶときに IndexOutOgBoundsExceptionが発生する可能性があるので 答えはC, Dになります。 と言うのがどうもわかりません。” 宜しくお願いします。

    • ベストアンサー
    • Java
  • スレッド

    問題集を読んでいて、どうしても意味がわからなかった部分があります。五択になっていて、私は 「notify()実行の条件は、呼び出し元のスレッドが待機状態にあるスレッドのロックフラグを取得していることである」 を選んだんですが、これは間違いでした。 解説には待機スレッドのロックフラグは必要ではない、とあるのですが、では逆に言うとなんの(何処の)ロックフラグが必要になるのでしょうか? ご存知の方がいらっしゃいましたら、教えて下さい。 宜しくお願い致します。

    • ベストアンサー
    • Java
  • デッドロック回避のためのwait() notify()

    学生です。最近javaの勉強をはじめました。 synchronized statementでデットロック回避のためにwait() notify()の使い方がよくわかりません。本にはwait()はスレッドがsynchronizedで獲得してあるロックを解放し、待機状態に入るとのことを書いてありましたが、なぜ、wait()をwhileループでまわすのでしょうか? それと、notifyは待機状態のスレッドに対して通知し、通知されたスレッドは待機状態から実行状態に移るとのことですが、whileループで再びwait()を実行し永遠に抜け出せないと思うのですがどうなんでしょうか? お手数ですが、詳しい方がいらしたら教えていただけないでしょうかお願いします。

  • C#のスレッド動作について

    下記はスレッドの中で永久ループさせるテストプログラムで、1秒毎にテキストボックス内の数値をインクリメントします。 【問題点1】 ※1と※2のコマンドを削除した状態(※3のみ)で正常な動作を期待していたのですが、実際にはフリーズ状態となり、カウント値が表示されません。 ※2のApplication.DoEvent()を実装するか、※3の替わりに※1に実装すると正常動作となります。 ExecThread実行中は他の処理を出来なくても、これを抜けた時点で表示処理に移るので表示される筈と思っていたのですが違う様です。 【問題点2】 Invokeの替わりにBeginInvokeを使えばExecThread実行中でも他の処理と並列処理されると思っていたのですが、スレッドを2個用意して試したところInvokeと全く変わらず、やはりフリーズ状態となります。 【問題点3】 ExecThreadを匿名メソッドにすると「フィールド初期化子は、静的でないフィールド、メソッド、又はプロパティ'iCount'を参照できません」のエラーとなり、「iCount」をstatic変数にするとOKになります。 匿名メソッドではインスタンス変数は使えないのでしょうか。 上記3項目についてネットで調べたのですがその様な記述は見当たりませんでした。 何か使い方が間違っているのでしょうか? 間違い点など、ご指摘頂ければ有難いです。 どうぞ宜しくお願いします。 private void ExecWorker() ← スレッド {   while (true)   {     Invoke(new Exec1Delegate(this.ExecThread)); ← BeginInvokeを使っても症状は同じ     iCount++;     Thread.Sleep(1000); ← ※1 このSleepが無いとフリーズする     Application.DoEvent(); ← ※2 これがあると※1のSleepが無くてもOK   } } delegate void ExecDelegate(); private void ExecThread() {   lbThread.Text = iCount.ToString(); ← 匿名メソッドにするとエラーになる   Thread.Sleep(1000); ← ※3 (※1のSleepと同時実装はしない) }

  • Javaのスレッドに関して質問です

    Assistantクラスを使い待機状態と再開を確認できるプログラムの作成 loafとrestartメソッドを設ける workメソッドが呼ばれる度loafを呼び出す Managerクラスを定義 checkメソッドを設け、Assistantをcheckし続ける loaf状態ならrestartさせる (Managerクラスはデーモンスレッド) ということなんですが、いまいちうまくいきません さぼっても復帰してくれません public class Assistant implements Runnable { private String name; private Chore c; public Assistant(String name, Chore c) { this.name = name; this.c = c; } public void run() { work(); } public void work() { while (true) { synchronized (c) { if (c.doEnd()) break; System.out.println(name + " : " + c.digest()); loaf(); } } } public synchronized void loaf() { try { c.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void restart() { c.notify(); } } public class Chore { private String name; private int step; private int id; public Chore(String name) { this.name = name; this.step = this.name.length(); this.id = 0; } public synchronized String digest() { String message = "" + id + name.charAt(id); try { Thread.sleep(500); } catch (InterruptedException ie) { } id++; return message; } public synchronized boolean doEnd() { return id >= step; } } public class Manager extends Thread { private String name; private Assistant a; public Manager(String name) { this.name = name; } public void run() { check(); } public void check() { a.restart(); } } public class Test { public static void main(String[] args) { Chore[] ch = { new Chore("掃除"), new Chore("プリント印刷"), new Chore("出欠データ入力") }; Assistant[] a = { new Assistant("あ", ch[0]), new Assistant("\tい", ch[1]), new Assistant("\t\tう", ch[2] }; Thread[] t = new Thread[a.length]; for (int i = 0; i < t.length; i++) { t[i] = new Thread(a[i]); } for (int i = 0; i < t.length; i++) { t[i].start(); } Manager m = new Manager("監査"); m.setDaemon(true); m.start(); for (int i = 0; i < t.length; i++) { try { t[i].join(); } catch( InterruptedException ie ) { } } }

    • ベストアンサー
    • Java
  • 非スレッドでsleepのように処理を指定時間止めるクラス・メソッドありませんか?

    現在、Struts、Servlet、Oracleの環境でDBロックの取得が出来なかった時に一定時間、間をおいて再度ロック取得を行いたいのですが、非スレッドでsleepメソッドのようなメソッド、クラスはありませんか? 教えて下さい。よろしくお願いします。

専門家に質問してみよう