我再次遇到其中一种情况,即停止/销毁/暂停线程是不可能的。 .interrupt()没有这个技巧,并且.stop()和.suspend()已被弃用。
很简单的例子:
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();
}
});
显然(?)这不起作用...我知道我可以使用Timer,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中创建线程启动/暂停/恢复/停止?
答案 0 :(得分: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的catch中重置被中断的状态
然而,在摇摆中,您可以使用javax.swing.Timer
让事件每隔一段时间运行一次,然后使用api
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();
}
});
答案 1 :(得分:3)
试试这个:
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
的情况下复制{{1}}。
答案 2 :(得分:1)
基本上,你让他们合作。你有一些共享的标志让他们看到他们应该做什么,以及当你 睡觉时,而不是你在某个共享监视器上wait
。然后,当你想控制线程时,你设置适当的标志和notify
监视器,这样如果线程正在等待,它将被唤醒并注意它应该暂停/停止/无论如何。显然,你需要对共享状态采取正常的关注,使用volatile变量,Atomic *对象或锁定来确保每个线程都能看到每个其他线程所做的更新。
任何非 - 合作都是有风险的,因为在手术中途可能会破坏状态。
答案 3 :(得分:1)
先发制人地阻止线程是危险的。这样做会导致死锁,资源泄漏等。相反,你应该使用合作信号机制。
向您希望它停止的线程发出信号,然后等待它执行此操作。线程应定期检查是否需要停止并做出相应的反应。
答案 4 :(得分: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本身有很多这样的例子!)。
答案 5 :(得分:0)
执行此操作的正确方法确实是拥有一个变量来确定何时应该停止Thread,退出其run方法。您可以找到有关如何正确执行此操作的详细信息here
答案 6 :(得分: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
}
}
}