1

我有一个 Runnable 类,它使用无限 while 循环在其 run 方法中连续执行操作。有时用户可能想要暂停/恢复操作。暂停线程的最佳方法是什么。我有两个想法:

第一的

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

第二

class Foo extends Runnable {
    @Override
    public void run() {
        while(true) {
            //pause if user wants to pause
            while(pauseFlag);
        }
    }
}
  • 在第一种情况下,当我在循环内使用 Thread.sleep 时,Netbeans IDE 发出警告不要在循环内使用 Thread.sleep。这是为什么?
  • 第二种情况下,当我使用无限空while循环时,这是性能开销吗?
  • 根据用户的选择,我应该更喜欢哪种方法(上面提到的或其他方法)暂停线程正在执行的操作?

因为它与同步无关,我不想使用等待/通知。

4

3 回答 3

4

在第一种情况下,当我在循环内使用 Thread.sleep 时,Netbeans IDE 发出警告不要在循环内使用 Thread.sleep。这是为什么?

我猜是因为 Netbeans 认为它​​不会测试循环条件并且代码会不必要地暂停。

在第二种情况下,当我使用无限空while循环时,这是性能开销吗?

嗯,是的。旋转线程将占用 CPU 并成为性能下降器。

根据用户的选择,我应该更喜欢哪种方法(上面提到的或其他方法)暂停线程正在执行的操作?

两者都不?我会使用 avolatile boolean pauseFlag来测试线程是否应该暂停,并结合等待/通知来取消暂停。或者您可以使用AtomicBoolean包装 avolatile boolean但也是我们可以同步的对象。也许是这样的:

// 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(...)循环。甚至sleep(1)比旋转要好得多。你真的需要比~1ms更快地取消暂停吗?但是等待/通知是最有效的。

因为它与同步无关,我不想使用等待/通知。

正如@Jon 所提到的,由于您试图在两个线程之间进行通信,因此这里需要某种同步。当然,您需要进行内存同步,否则任何更新pauseFlag都不能保证在线程之间共享。这是由 on 的volatile原语处理的pauseFlag。通过使用等待/通知(需要synchronized),您的代码可以更有效地唤醒。

于 2013-10-08T17:43:02.257 回答
3

因为它与同步无关,我不想使用等待/通知。

它与同步有关大概您的用户交互发生在不同的线程上 - 所以您试图在两个线程之间同步信号。

你不应该在这里使用Thread.sleep 紧密循环。在这里使用更高级别的构造中的任何一个wait/或类似的东西都是正确的方法。notifyjava.util.concurrent

请注意,如果没有任何内存障碍,pauseFlag从一个线程对您所做的更改可能不会在另一个线程中被注意到,因此您至少希望使其易失。

于 2013-10-08T17:33:00.577 回答
1

您正在同步线程之间的状态更改,因此我将使用 wait(),但是另一种方法是使用睡眠。你可以忙着等待,但你不会获得太多,但你会失去一个 CPU。

于 2013-10-08T17:32:37.997 回答