イベントディスパッチスレッド(EDT)は、GUIを安全に読み取ったり更新したりできる唯一のスレッドです。
一時停止ボタンは、イベントディスパッチスレッドでオン/オフ変数を設定する必要があります。
時間のかかる操作とループは、EDTに含めるべきではありません。(ループは、変数をチェックする以外に何もせずに継続的に実行するべきではありません。そうしないと、CPUをすべて簡単に使い果たす可能性があります。他に何もすることがない場合は、チェックしてから、Thread.sleep()
しばらくの間(たとえば、100ms)呼び出します。)
オン/オフ変数がオフに設定されていることを証明できるが、それでも常にオンとして読み取られる場合は、変数の値が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();
}
});
}
}
(実際のアプリケーションによっては、これをクリーンアップするために多くのことを行うことができますが、アイデアは得られます。)