2011-08-21 66 views
2

我再次遇到過這樣的情況:只能停止/銷燬/暫停線程。 .interrupt()不會執行此操作,不推薦使用.stop()和.suspend()。爲什麼在Java中停止線程很困難?

很簡單的例子:

public class TimerThread extends Thread { 

    private JPanel colorPanel; 

    public TimerThread(JPanel colorPanel) { 
     this.colorPanel = colorPanel; 
    } 

    public void run() { 
     while (true) { 
      try { 
       Thread.sleep(1000); 
       colorPanel.repaint(); 
      } catch (Exception ex) { 
       //do Nothing 
      } 
     } 
    } 
} 

這樣做是什麼重繪一定的JPanel每秒改變其顏色。我要開始從另一個類停止線程像這樣:(?)

timer = new Thread(new TimerThread(colorPanel)); 

    startButton.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      timer.start(); 
     } 
    }); 

    stopButton.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      timer.interrupt(); 
     } 
    }); 

顯然,這並不工作...我知道我可以用一個定時器,一個SwingWorker的或聲明的計時器爲timer = new TimerThread(colorPanel);和在run方法中使用布爾值而不是「true」,但我被要求將計時器聲明爲「線程」,而不是別的。

讓我驚訝的(或這是愚蠢的?),即使這並不工作:

startButton.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      timer = new Thread(new TimerThread(colorPanel)); 
      timer.start(); 
     } 
    }); 

    stopButton.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      timer.interrupt(); 
      timer = null; 
     } 
    }); 

所以我的問題很簡單:你如何使線程開始/暫停/恢復/停止在Java中?

+9

如果您仍然遇到這種情況,您需要重新考慮如何使用線程。線程應該控制自己的生命週期,而不是在外部暫停/停止。這是一個設計問題。 – skaffman

+0

@skaffman再次閱讀OP:這是作業,他只能使用一個線程。 – toto2

+0

確實@total2,它可能是多麼不幸,如果更高階的命令你使用線程你不能提供的東西,與SwingWorker實現... – Matthias

回答

5

當你得到一箇中斷時,你應該開始清理並返回a.s.a.p。 (或者至少是復位中斷狀態)

while (true) { 
    try { 
     Thread.sleep(1000); 
     colorPanel.repaint(); 
    } catch(InterruptedException e){//from sleep 
     return;//i.e. stop 
    } catch (Exception ex) { 
     //do Nothing 
    } 
} 

另一種方式是在條件檢查Thread.interrupted()(但你需要重置InterruptedException的

漁獲

但是中斷狀態在搖擺,你可以使用javax.swing.Timer讓事件運行,每隔一段時間,並停止與那

javax.swing.Timer timer = new Timer(1000,new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
     colorPanel.repaint(); 
    } 
}); 
timer.setRepeats(true); 

startButton.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
     timer.start(); 
    } 
}); 

stopButton.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
     timer.stop(); 
    } 
}); 
+0

return;做了它,謝謝 – Matthias

1

你讓他們合作,基本上。你有一些共享的標誌,讓他們看到他們應該做什麼,並且每當你睡覺時,而你wait在一些共享的顯示器上。然後,當你想控制線程時,你需要設置合適的標誌和監視器,以便如果線程正在等待,它將喚醒並注意到它應該掛起/停止/不管。顯然你需要在共享狀態周圍採取正常的謹慎態度,使用volatile變量,Atomic *對象或鎖定來確保每個線程都能看到每個其他線程所做的更新。

任何東西合作是有風險的,因爲有可能在操作中途損壞國家。

1

搶先制止線程是危險的。這樣做會導致死鎖,資源泄漏等。相反,你應該使用合作的信號機制。

發信號給您希望它停止的線程,然後等待它。線程應定期檢查是否需要停止並作出相應的反應。

3

的API試試這個:

public class TimerThread extends Thread { 

    private volatile boolean stop = false; 
    private JPanel colorPanel; 

    public TimerThread(JPanel colorPanel) { 
     this.colorPanel = colorPanel; 
    } 

    public void stopTimer() { 
     stop = true; 
    } 

    public void run() { 
     while (stop == false) { 
      try { 
       Thread.sleep(1000); 
       colorPanel.repaint(); 
      } catch (Exception ex) { 
       //do Nothing 
      } 
     } 
    } 
} 

// Why new Thread(new TimerThread(...))? 
// timer = new Thread(new TimerThread(colorPanel)); 

timer = new TimerThread(colorPanel) 

startButton.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
     timer.start(); 
    } 
}); 

stopButton.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
     timer.stopTimer(); 
    } 
}); 

也看看here看看如何複製stop現在它已被棄用。

+0

爲什麼新線程(新的TimerThread(...))?因爲我只能使用「線程」。 如果我嘗試啓動,停止然後重新啓動,會不會引發異常? – Matthias

+0

我的解決方案不處理重新啓動線程。你可以重載'start'來設置'stop'回到'false',然後調用'super.start()'。 – Behrang

+0

@Matthias然後你的類TimerThread應該實現Runnable,不能擴展Thread類,你可以將Runnable實例傳遞給Thread構造函數。 – Andrey

0

這樣做的正確方法的確有一個變量,該變量確定何時應該停止線程,退出其運行方法。你可以找到關於如何做到這一點正確here

1

而是循環while (true)的更多信息,你應該循環,而線程沒有中斷:

@Override public void void() { 
    // some kind of initialization... 
    while (!Thread.currentThread().isInterrupted()) { 
    try { ... 
    } catch (InterruptedException e) { 
     Thread.currentThread().interrupt(); // ensure interrupt flag is set 
    } 
    } 
    // some kind of cleanup 
} 

如果InterruptedException不再受你while塊中拋出,要麼你不使用阻塞操作(並且只需在該線程上調用Thread.interrupt()會在下一次迭代時停止它),或者使用一些阻塞調用,這些調用的表現並不好(JCL本身中有很多這樣的例子!) 。

0

使用此解決方案,您不會獲得可以通過等待/通知或中斷獲得的「即時」更新,但如果您不介意第二次延遲的一小部分,它應該完成這項工作。

volatile boolean stopped = false; 
volatile boolean paused = false; 

pauseButton.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
     paused = true; 
    } 
}); 

resumeButton.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
     paused = false; 
    } 
}); 

stopButton.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
     stopped = true; 
    } 
}); 

... TimerThread 

public void run() { 
    while (stopped == false) { 
     try { 
      Thread.sleep(1000); 
      if (stopped) 
       break; 
      if (!paused) 
       colorPanel.repaint(); 
     } catch (Exception ex) { 
      //do Nothing 
     } 
    } 
}