所以我创建了一个带有停止按钮的基本swing接口,点击它会停止计数线程。当应用程序启动时,线程实例将分配一个runnable
类,该类执行计数循环并将其记录在控制台中。 runnable
接口中有一个方法将volatile变量设置为false,基本上应该停止线程并在停止按钮上调用它,但为什么不停止循环?这是我的代码。
ParentContainer.java
public class ParentContainer extends JFrame implements ActionListener, WindowListener {
private static final long serialVersionUID = 1L;
private JButton btnStop;
private static CountRunnable cr;
public ParentContainer() {
Container cp = getContentPane();
cp.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));
btnStop = new JButton("Stop Counting");
cp.add(btnStop);
SymAction lSymAction = new SymAction();
btnStop.addActionListener(lSymAction);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Counter");
setSize(200, 90);
setVisible(true);
}
public static void main(String[] args) {
// Run GUI codes in Event-Dispatching thread for thread safety
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new ParentContainer(); // Let the constructor do the job
}
});
cr = new CountRunnable();
Thread t1 = new Thread(cr, "MyRunnable");
t1.start();
}
class SymAction implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
Object object = evt.getSource();
if (object == btnStop) { btnStop_actionPerformed(evt); }
}
}
void btnStop_actionPerformed(ActionEvent evt)
{
cr.stop();
}
@Override
public void windowActivated(WindowEvent arg0) { }
@Override
public void windowClosed(WindowEvent arg0) { }
@Override
public void windowClosing(WindowEvent arg0) { }
@Override
public void windowDeactivated(WindowEvent arg0) { }
@Override
public void windowDeiconified(WindowEvent arg0) { }
@Override
public void windowIconified(WindowEvent arg0) { }
@Override
public void windowOpened(WindowEvent arg0) { }
@Override
public void actionPerformed(ActionEvent arg0) { }
}
CountRunnable.java
public class CountRunnable implements Runnable {
public static volatile boolean keepRunning;
private int count = 1;
@Override
public void run() {
keepRunning = true;
while (keepRunning)
{
for (int i = 0; i < 100000; ++i) {
System.out.println(count + "");
++count;
// Suspend this thread via sleep() and yield control to other threads.
// Also provide the necessary delay.
try {
Thread.sleep(10); // milliseconds
}
catch (InterruptedException ex) {
}
}
}
}
public void stop()
{
keepRunning = false;
}
}
答案 0 :(得分:1)
因为它首先要完成内部for循环
for (int i = 0; i < 100000; ++i)
在进入外部while循环的下一次迭代之前再次检查keepRunning
布尔值。
只需删除for循环即可。
答案 1 :(得分:1)
在停止状态时,请务必经常检查状况。目前,你有一个运行一段时间的循环,你只能在循环结束时看到你的检查结果。
为确保循环在迭代中结束,您可以在循环内添加以下检查。
if(!keepRunning) {
break;
}
您也可以尝试不同的解决方案。因为经常使用这种停止线程的模式,所以你也可以使用SwingWorker
作为你的子任务,这个类给出了相当多的有用的实用方法来停止,并且从子任务中更新gui线程安全(所以对于例如,您可以在gui中显示count而不是命令行)
更改代码以使用SwingWorker
很容易,在扩展SwingWorker
时,它需要2个元素,a&#34;最终结果&#34;以及&#34;待定结果&# 34。
SwingWorker
的示例:
SwingWorker<String, String> task = new SwingWorker<String, String>(){
private int count = 1;
@Override
public List<Integer> doInBackground() throws Exception {
while (!isCancelled()) {
for (int i = 0; i < 100000; ++i) {
publish(count + "");
++count;
Thread.sleep(10); // milliseconds
}
}
return count + "";
}
@Override
protected void process(List<Integer> chunks) {
gui.setText(chunk.get(chunk.size() - 1));
}
@Override
protected void done() {
try {
gui.setText(this.get());
} catch(InterruptedException | ExecutionException ex) {
ex.printSTackTrace();
}
}
}
task.execute();
// Later:
task.cancel(false);
请注意,建议使用false取消,因为使用true表示执行计数器的线程将被中断,导致Thread.sleep()抛出异常。
如果您的任务的目的只是计算一个数字,那么使用timer(确保导入正确的)类可能更容易,使用该类就像以下一样简单: / p>
int delay = 10; //milliseconds
ActionListener taskPerformer = new ActionListener() {
int count = 0;
public void actionPerformed(ActionEvent evt) {
count++;
gui.setText(count + "");
// System.out.println(count + "");
}
};
Timer task = new Timer(delay, taskPerformer);
task.setCoalesce(false); // SOmetimes, executions can be missed because other programs
task.setRepeating(true);
task.start();
// Later:
task.stop();
请注意,使用此计时器解决方案,您可以通过调用start()
重新启动它,这与我向您展示的其他解决方案不同。