暂停和恢复SwingWorker.doInBackground()

我有一个基本的Swing UI,只有一个标记为“Play”的按钮。 按下按钮时,标签变为“暂停”。 按下按钮后,它会变为“恢复”。

在“Play”上我实例化并执行SwingWorker。 我想要的是能够暂停这个线程(不取消它)并根据上述按钮按下恢复它。 但是,我不想在doInBackground()中使用Thread.sleep()。 这似乎有点hackish。 有没有办法让运行doInBackground的线程阻塞?

暂停和恢复SwingWorker.doInBackground()

首先,您必须确保正在执行的后台任务可以暂停,否则问题没有意义。 因此,假设任务可以暂停,然后您可以扩展SwingWorker类并使用简单的标志变量来创建自己的可调工作程序来控制后台线程状态: 暂停不暂停

public abstract class PausableSwingWorker extends SwingWorker { private volatile boolean isPaused; public final void pause() { if (!isPaused() && !isDone()) { isPaused = true; firePropertyChange("paused", false, true); } } public final void resume() { if (isPaused() && !isDone()) { isPaused = false; firePropertyChange("paused", true, false); } } public final boolean isPaused() { return isPaused; } } 

子类可能会检查isPaused()状态,以便有效地继续执行任务。 例如:

 PausableSwingWorker worker = new PausableSwingWorker() { @Override protected Void doInBackground() throws Exception { while (!isCancelled()) { if (!isPaused()) { // proceed with background task } else { Thread.sleep(200); // Optional sleep to avoid check status continuously } } return null; } }; 

您还可以向worker添加PropertyChangeListener并侦听paused属性更改:

 worker.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("paused".equals(evt.getPropertyName())) { System.out.println("Old status: " + evt.getOldValue()); System.out.println("New status: " + evt.getNewValue()); } } }); 

示例(更新以使用PropertyChangeListener)

这是一个完整的例子。 请注意,如果工人被停止,则不能再暂停或恢复工作人员。

 import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; public class Demo { private void createAndShowGUI() { final JTextArea textArea = new JTextArea(20, 50); final PausableSwingWorker worker = new PausableSwingWorker() { @Override protected Void doInBackground() throws Exception { while (!isCancelled()) { if (!isPaused()) { publish("Writing..."); } else { Thread.sleep(200); } } return null; } @Override protected void process(List chunks) { String text = String.format("%s%n", chunks.get(chunks.size() - 1)); textArea.append(text); } }; worker.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("paused".equals(evt.getPropertyName())) { String text = (Boolean)evt.getNewValue() ? "Paused..." : "Resumed..."; textArea.append(String.format("%s%n", text)); } } }); Action pause = new AbstractAction("Pause") { @Override public void actionPerformed(ActionEvent e) { worker.pause(); } }; Action resume = new AbstractAction("Resume") { @Override public void actionPerformed(ActionEvent e) { worker.resume(); } }; Action stop = new AbstractAction("Stop") { @Override public void actionPerformed(ActionEvent e) { worker.cancel(true); } }; JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); buttonsPanel.add(new JButton(pause)); buttonsPanel.add(new JButton(resume)); buttonsPanel.add(new JButton(stop)); JPanel content = new JPanel(new BorderLayout(8, 8)); content.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); content.add(new JScrollPane(textArea), BorderLayout.CENTER); content.add(buttonsPanel, BorderLayout.SOUTH); JFrame frame = new JFrame("Demo"); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { if (!worker.isDone()) { worker.cancel(true); } e.getWindow().dispose(); } }); frame.add(content); frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); worker.execute(); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new Demo().createAndShowGUI(); } }); } abstract class PausableSwingWorker extends SwingWorker { private volatile boolean isPaused; public final void pause() { if (!isPaused() && !isDone()) { isPaused = true; firePropertyChange("paused", false, true); } } public final void resume() { if (isPaused() && !isDone()) { isPaused = false; firePropertyChange("paused", true, false); } } public final boolean isPaused() { return isPaused; } } }