事件调度线程 (EDT) 是唯一可以安全读取或更新 GUI 的线程。
暂停按钮应该在事件调度线程中设置开/关变量。
耗时的操作和循环不应该在 EDT 中。(循环也不应该连续运行,除了检查变量之外什么都不做,否则它很容易吃掉你所有的 CPU。如果它没有别的事情要做,它应该检查,然后调用Thread.sleep()
一段时间(比如 100 毫秒)。)
如果您可以证明 on/off 变量被设置为 OFF,但它始终被读取为 ON,则可能是该变量的值没有从 EDT 复制到工作线程。制作它volatile
,或synchronize
访问它,或使用AtomicReference
,或在 EDT 中使用SwingUtilities.invokeAndWait()
.
SwingWorker
可能是最简单的方法,在这里。在方法中实现您的耗时操作和开/关检查,并在doInBackground()
方法中实现您的 GUI 更新done()
。
public enum State {
RUNNING, STOPPED
}
public class ThreadSafeStateModel {
private State state = State.STOPPED;
public synchronized void stop() {
state = State.STOPPED;
}
public synchronized void start() {
state = State.RUNNING;
}
public boolean isRunning() {
return state == State.RUNNING;
}
}
public class ExpensiveProcessWorker extends SwingWorker<Void, Void> {
private final ThreadSafeStateModel model;
public ExpensiveProcessWorker(ThreadSafeStateModel model) {
this.model = model;
}
@Override // Runs in background
protected Void doInBackground() throws Exception {
while (model.isRunning()) {
// do one iteration of something expensive
}
return null;
}
@Override // Runs in event dispatch thread
protected void done() {
// Update the GUI
}
}
public class StopButton extends JButton {
public StopButton(final ThreadSafeStateModel model) {
super(new AbstractAction("Stop") {
@Override
public void actionPerformed(ActionEvent e) {
model.stop();
}
});
}
}
public class StartButton extends JButton {
public StartButton(final ThreadSafeStateModel model) {
super(new AbstractAction("Start") {
@Override
public void actionPerformed(ActionEvent e) {
model.start();
new ExpensiveProcessWorker(model).execute();
}
});
}
}
(根据实际应用程序,可以做很多事情来清理它,但你明白了。)