1

無限 while ループを使用して run メソッドで操作を継続的に実行する Runnable クラスがあります。ユーザーが操作を一時停止/再開したい場合があります。スレッドを一時停止する最良の方法は何ですか。私には2つの考えがあります:

最初

class Foo extends Runnable {
    @Override
    public void run() {
    while(true) {
        if(pauseFlag)
           try{
              Thread.sleep();
           } catch(InterrruptedException ie) {//...}
    }
}

2番目

class Foo extends Runnable {
    @Override
    public void run() {
        while(true) {
            //pause if user wants to pause
            while(pauseFlag);
        }
    }
}
  • 最初のケースでは、ループ内で Thread.sleep を使用すると、Netbeans IDE がループ内で Thread.sleep を使用しないようにという警告を発行します。何故ですか?
  • 2番目のケースでは、無限の空の while ループを使用すると、パフォーマンスのオーバーヘッドになりますか?
  • ユーザーの選択に応じて、スレッドによって実行されているアクションを一時停止するには、どの方法(上記またはそれ以外)を選択する必要がありますか?

同期とは関係ないので、wait/notify は使いたくない。

4

3 に答える 3

4

最初のケースでは、ループ内で Thread.sleep を使用すると、Netbeans IDE がループ内で Thread.sleep を使用しないようにという警告を発行します。何故ですか?

Netbeans は、ループ状態をテストしないと考えており、コードが不必要に一時停止するためだと思います。

2 番目のケースでは、無限の空の while ループを使用すると、パフォーマンスのオーバーヘッドになりますか?

そうそう。スレッドのスピンは CPU を消費し、パフォーマンス シンクになります。

ユーザーの選択に応じて、スレッドによって実行されているアクションを一時停止するには、どの方法(上記またはそれ以外)を選択する必要がありますか?

ない?スレッドを一時停止する必要があるかどうかをテストするために使用し、volatile boolean pauseFlag待機/通知と組み合わせて一時停止を解除します。またはAtomicBoolean、 a をラップするvolatile booleanが、同期できるオブジェクトでもある an を使用できます。たぶん次のようなもの:

// using `AtomicBoolean` which wraps a `volatile boolean` but is const object
// NOTE: we _can't_ synchronized on Boolean, needs to be constant object reference
private final AtomicBoolean pauseFlag = new AtomicBoolean(false);
...
while (!Thread.currentThread().isInterrupted()) {
    if (pauseFlag.get()) {
       synchronized (pauseFlag) {
          // we are in a while loop here to protect against spurious interrupts
          while (pauseFlag.get())) {
             try {
                pauseFlag.wait();
             } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                // we should probably quit if we are interrupted?
                return;
             }
          }
       }
    }
    ...
}
...
public void pause() {
   pauseFlag.set(true);
}
...
public void resume() {
   pauseFlag.set(false);
   synchronized (pauseFlag) {
       pauseFlag.notify();
   }
}

sleep(...)2つのうちの1つを選ばなければならないとしたら、ループを選ぶと思います。偶数sleep(1)はスピンよりもはるかに優れています。~1ms よりも早く一時停止を解除する必要がありますか? ただし、待機/通知が最も効率的です。

同期とは関係ないので、wait/notify は使いたくない。

@Jon が述べたように、2 つのスレッド間で通信しようとしているため、ここでは何らかの同期が必要です。確かに、メモリの同期が必要です。そうしないと、への更新pauseFlagがスレッド間で共有されることが保証されません。これは、volatileプリミティブ onによって処理されpauseFlagます。wait/notify (これには が必要synchronizedです) を使用することで、コードはウェイクアップに関してはるかに効率的になります。

于 2013-10-08T17:43:02.257 に答える