web-dev-qa-db-ja.com

ブール値が状態を変更するまで待ちます

ブール値が次のように変化するのを待つスレッドがあります。

while(!value)
{
  Thread.sleep(1000)
}
// Do some work after change of the value

これは、これを行うための私の好みの方法ではなく、CPUの大量消費の原因です。

ブール値が状態を変更するまで、スレッドをブロックする方法はありますか?

40
Marcel Höll

これは、これを行うための私の好みの方法ではなく、CPUの大量消費の原因です。

それが実際に動作するコードである場合は、そのままにしてください。ブール値を1秒間に1回チェックすると、測定可能なCPU負荷は発生しません。まったくありません。

本当の問題は、値をチェックするスレッドが、キャッシュのために任意の長い時間に発生した変更を認識しない可能性があることです。スレッド間で値が常に同期されるようにするには、変数定義にvolatileキーワードを追加する必要があります。

private volatile boolean value;

他の回答で説明されている通知ベースのソリューションを使用する場合など、synchronizedブロックにアクセスを配置しても同じ効果があることに注意してください。

72

ビジー待機を回避するメカニズムが必要です。老人 wait/notifyメカニズムには落とし穴があるので、Java.util.concurrentライブラリ、たとえば CountDownLatch

public final CountDownLatch latch = new CountDownLatch(1);

public void run () {
  latch.await();
  ...
}

そして、反対側の呼び出しで

yourRunnableObj.latch.countDown();

ただし、スレッドが必要になるまで待機するだけでスレッドを開始することは、まだ最善の方法ではありません。条件が満たされたときに実行する必要がある作業をタスクとして送信するExecutorServiceを使用することもできます。

45
Marko Topolnik

wait-notify

private Boolean bool = true;
private final Object lock = new Object();

private Boolean getChange(){
  synchronized(lock){
    while (bool) {
      bool.wait();
    }
   }
  return bool;
}
public void setChange(){
   synchronized(lock){
       bool = false;
       bool.notify();
   }
}

おそらくこれで問題が解決するでしょう。変更を行うたびに、待機を解除するchange()メソッドを呼び出すことに注意してください。

Integer any = new Integer(0);

public synchronized boolean waitTillChange() {
    any.wait();
    return true;
}

public synchronized void change() {
    any.notify();
}
2
luiso1979

私はそのような場合にミューテックスメカニズムを使用することを好みますが、本当にブール値を使用したい場合は、揮発性として宣言して(スレッド間で変更の可視性を提供するため)、そのブール値を条件としてボディレスサイクルを実行する必要があります:

//.....some class

volatile boolean someBoolean; 

Thread someThread = new Thread() {

    @Override 
    public void run() {
        //some actions
        while (!someBoolean); //wait for condition 
        //some actions 
    }

};
1
oleg.lukyrych