Search code examples
javamultithreadingswingswingworker

What did I wrong when I want to stop SwingWorker in this case?


public class Worker extends SwingWorker<Integer, String> {
private JLabel screen;

    public Worker(JLabel screen) {
        this.screen = screen;
    }

    @Override
    protected Integer doInBackground() throws Exception {
        for (; ; ) {
            publish(String.valueOf(Calendar.getInstance().getTimeInMillis()));
        }
    }

    @Override
    protected void process(List<String> chunks) {
        screen.setText(chunks.get(0));
    }
}

And in Form:

    public class Form extends JPanel{
    private JButton startButton;
    private JPanel rootPanel;
    private JButton stopButton;
    private JLabel screen;
    private Worker worker;

    public Form() {
        startButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                worker = new Worker(screen);
                worker.execute();
            }
        });
        stopButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                worker.cancel(true);
                System.out.println(worker.isDone());
                System.out.println(worker.isCancelled());
            }
        });
    }

    private void createUIComponents() {
        rootPanel = this;
    }
}

I tried to write same code with Tread, but it doesn't work too. And console output after click on stopButton:

true

true

So, worker have done, but program still continue show milliseconds. What is a post-death life? And in case of using Thread same thing: method isAlive() return "false".


Solution

  • Based on your code, it looks like you need a worker with a loop to keep running until the master thread tells it to stop running, which is done with worker.cancel(true);. The problem is that you are canceling it, but doing nothing to signal the loop itself to stop iterating. To fix this, you should change

    for (; ; ) {
        publish(String.valueOf(Calendar.getInstance().getTimeInMillis()));
    }
    

    to

    while(!isCancelled()){
        publish(String.valueOf(Calendar.getInstance().getTimeInMillis()));
    }
    

    Note the phrasing of 'isCancelled' from the java docs:

    isCancelled()

    Returns true if this task was canceled before it completed normally. Since the loop never closes on its' own, it will never complete normally.