質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • Java

    14092questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

フラグを監視するプログラム

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 4
  • VIEW 626

1221_hima

score 12

タイトルの通り、あるクラスのフラグを監視するプログラムを書いています(あるプログラムの一部として)。

メインスレッドとは別に、1つスレッドを走らせてその中でwhile文を使ってメイン関数を持つクラスのフラグを監視しています。

@Override
public void run(){
  while(true){
     if(Test.flag){
         //はじめflagはfalse
       break;
     }
  }
   System.out.println("while文を抜けました");
}

単純にこのようにかくとflagをメイン関数内でtrueに変えてもwhile文を抜け出すことができないのですが、while文の中にThread.sleep()関数を使って少し待つとwhile文を抜け出すことができました。

こういったflgaなどを監視するプログラムを作る場合Thread.sleepやTimerを使って待たなければwhile文を抜け出すことはできないのでしょうか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • asahina1979

    2018/05/05 11:55

    抜けてないのに「while文を抜けました」出力するのは置いておいて スリープしてないとこの無限ループにCPUリソースがとられ過ぎますが数倍の時間をかけて終わるとは思いますが。

    キャンセル

  • asahina1979

    2018/05/05 11:56

    あとは対象が static であるならばですね

    キャンセル

  • 1221_hima

    2018/05/05 12:24

    このような監視プログラムを書く場合どういうコードを書くのが適切なのでしょうか

    キャンセル

回答 3

checkベストアンサー

+6

訂正:umyuさんご指摘の点を訂正します。

Thread.sleepやTimerを使って待たなければwhile文を抜け出すことはできないのでしょうか?

いえ、必ずしもそうではありません。質問者さんのコードの詳細が不明なので抜け出せなかった原因をはっきりと指摘できませんが、少なくともTest.flagはvolatile修飾子を付与しなければなりません。例えば、Test.flagvolatile修飾子を付与するといった「実行順序の同期に関する配慮」をしなければなりません。理由については「メモリバリア」「メモリフェンス」といった用語を調べるとよいと思います。

class Test {
  static volatile boolean flag;
  ...
}

 

ただ通常はご質問のような方法(CPUを消費し続けながら期待する状態変化を検出すること=ビジーループ)は使いません。そうではなく「変化がおきるまでスレッドをブロックしてくれるような機構」を用います。Javaでそれを行う最も原始的な方法はsynchronized文Object#waitObject#notifyになります。

class Test {
  Object lock = new Object(); // 参照型のインスタンスなら何でもよい
  boolean state; //(注)

  // 状態を変更する側(スレッド#1で動かす)
  void change() throws InterruptedException {
    synchronized (lock) {
      state = true;
      lock.notify();
    }
  }

  // 状態変化を待つ側(スレッド#2で動かす)
  void waitForChange() throws InterruptedException {
    synchronized (lock) {
      while (!state) {
        lock.wait();
      }
    }
  }
  ...
}


(注:元の回答ではvolatileを付与していましたが、stateのread/writeが必ずsynchronizedブロック内にしかない上のような例ではvolatileは必要ないので上の例からvolatileを取りました)

lockはどんな参照型インスタンスでもよく、上の例では例えばthisとかTest.classを使ってもかまいません。thisを使うなら

  void synchronzied change() throws InterruptedException {
    state = true;
    lock.notify();
  }


と書けますしTest.classを使うなら

  static void synchronzied change() throws InterruptedException {
    state = true;
    lock.notify();
  }


と書けます。一定時間sleepなどで待機しながら変化を待つこともできますが、「状態が変化してもsleepで待っている間は変化を検知できないので即時性に劣る方法」ということになります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/07 14:30

    わかりやすい説明ありがとうございます!
    スレッドの制御でうまく処理できました

    キャンセル

  • 2018/05/07 15:31 編集

    >KSwordOfHasteさんへ
    synchronzied を使う限りでは、volatile宣言 は不要です。
    https://www.ibm.com/developerworks/jp/java/library/j-jtp10264/index.html
    ◇↓はjava.util.concurrent.atomic.AtomicBooleanを使った同期サンプルです。
    https://wiki.sei.cmu.edu/confluence/display/java/VNA00-J.+Ensure+visibility+when+accessing+shared+primitive+variables
    ◇LCK00-J. 信頼できないコードから使用されるクラスを同期するにはprivate finalロックオブジェクトを使用する
    https://www.jpcert.or.jp/java-rules/lck00-j.html

    以上、参考情報としてだけ置いておきます。横レス失礼致しました。

    キャンセル

  • 2018/05/07 15:45

    ご指摘ありがとうござました。以前本サイトでvolatileが必要という話を訊いたのですが理解がまだ曖昧だったようです。再度確認してみます。

    キャンセル

  • 2018/05/07 17:48 編集

    以前https://teratail.com/questions/79476でyohhoyさんにvolatileが必要と指摘していただいたのですが、そのケースはsynchronized有りと無しの2つのブロックでの同一の変数アクセスというかなり特殊なケースだったためvolatileが必要で、本件の自分の回答にあるように参照・更新が全てsynchronizedブロックに含まれる通常のケースではvolatileは不要であるという点が理解できていませんでした。言語仕様書の17.4 Memory Modelが仕様の全容であると思いますが、完璧に理解するのがさらりとできるほどに自分にとって易しい内容ではなかったです。じっくり理解しようと思います。
    とりあえずは本回答を適切に直せるように考えてみます。
    ---
    ==>回答を訂正してみました。05/07 17:58

    キャンセル

+1

マルチスレッドと言っても、コードが完全に並行して実行されるというもんでもないです。
実行されるコードは常に一つで、それを切り替えて複数実行されるように見せてるだけなんですね。
んで、そのコードを切り替えるタイミングですが、一つはコードが待ちに入ったとき(Thread.Sleepや各種event、システムコール呼び出しなどなど)、と、あとはタイマ割り込みなどの時間的なイベントがあったとき、となります。
その時間的なイベント、ですが、実際にどんだけの時間スロットで切り替えられるというのはよくは知りませんが、そこらへんぐぐると、いろいろ解説が出てくると思いますんで調べてみてください。

ということで、提示されてるコードだと、sleepがない場合、次にタスクの切り替えが起きるのは数ms後になる(かもしれない?)ということになるってことになりますね

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/07 14:32

    回答ありがとうございました!
    OSの授業を取っていたのでなんとなくイメージは湧いていたのですが実際書いたコードがどのように動いてるかもっと詳しく勉強した方が為になりそうですね、、、

    キャンセル

-1

デザインパターンの「garded wait」と呼ばれるものがあります。↓動作未確認。

@Override
public void run(){
  while(!Test.flag){
         //はじめflagはfalse
       wait();//←追加しました
  }
   System.out.println("while文を抜けました");
}

//別の場所
Test.flag = true;
notifyAll();
//↑の二行で当該スレッドがループを脱出する。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/07 14:31

    回答ありがとうございました!

    キャンセル

関連した質問

同じタグがついた質問を見る

  • Java

    14092questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。