2013-10-08 113 views
1

我有一個Runnable類,它在運行方法中使用無限while循環連續執行操作。有時用戶可能想要暫停/恢復操作。什麼是暫停線程的最佳方法。我有兩個想法:暫停線程的最佳方法?

FIRST

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); 
     } 
    } 
} 
  • FIRST情況下,當我使用了Thread.sleep內循環NetBeans IDE的問題警告不要在內部循環中使用Thread.sleep。這是爲什麼?
  • SECOND的情況下,當我使用無限空while循環,是一個性能開銷?
  • 根據用戶的選擇,哪種方法(上面提到的或其他方法)應該更喜歡暫停正在執行的操作?

因爲它與同步無關,所以我不想使用wait/notify。

+0

我不會編程一個'Thread'來讓它暫停。實施它等待一些事情。 –

回答

4

在第一種情況下,當我在內部循環中使用Thread.sleep時,Netbeans IDE發出警告,不要在內部循環中使用Thread.sleep。這是爲什麼?

我猜是因爲Netbeans認爲它不會測試循環條件,代碼會不必要地暫停。

在SECOND情況下,當我使用無限空while循環時,性能開銷是多少?

呃是的。旋轉一個線程將需要一個CPU併成爲一個性能接收器。

哪個方法(上面提到的或其他方法)我應該更喜歡根據用戶的選擇暫停正在執行的操作?

都不是?我會使用volatile boolean pauseFlag來測試線程是否應該暫停,並結合wait/notify來取消暫停。或者,您可以使用AtomicBoolean,它包含volatile 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更快的停頓嗎?但等待/通知是最有效的。

因爲它與同步無關,所以我不想使用wait/notify。

正如@Jon提到的那樣,由於您嘗試在兩個線程之間進行通信,因此需要進行某種同步。當然,你需要有內存同步,否則任何更新pauseFlag將不能保證在線程之間共享。這由pauseFlag上的volatile原語處理。通過使用wait/notify(需要​​),您的代碼可以更有效地喚醒。

1

您正在同步線程之間的狀態更改,因此我將使用wait(),但替代方法是使用sleep。你可以等待,但是你不會獲得太多的收益,但是你會失去一個CPU。

3

因爲它與同步無關,我不想使用等待/通知。

它有一切做同步。據推測,你的用戶交互發生在另一個線程上 - 所以你試圖在兩個線程之間同步信號。

你不應該使用Thread.sleep在這裏一個嚴密的循環。 wait/notify或其他類似的使用java.util.concurrent中的更高級別構造的方法是正確的方法。

需要注意的是,沒有任何記憶障礙,改變你的pauseFlag從一個線程可能無法在不同的線程注意到了,所以你至少想讓它揮發。

+0

如果我使用java.util.concurrent.atomic.AtomicInteger作爲標誌使用,那麼我會鬆散緊密循環的CPU週期。我應該使用等待/通知還是緊密循環? – Madeyedexter

+1

@Madeyedexter:我沒有建議使用AtomicInteger,是嗎?我建議使用'java.util.concurrent'(例如'Semaphore')或'wait' /'notify'的更高層次的線程構造。你絕對*不應該執行緊密的循環。 –

+0

好的。我會看到它。 – Madeyedexter