Quello di seguito è un esempio che ho appena scritto per mostrare come gestire
correttamente sospensione/ripresa in uno SwingWorker.
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class FrameProva extends JFrame {
public FrameProva() {
super("Prova Task");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(300, 200);
setLocationRelativeTo(null);
setLayout(new FlowLayout());
JButton btnSospendi = new JButton("SOSPENDI");
JButton btnRiprendi = new JButton("RIPRENDI");
add(btnSospendi);
add(btnRiprendi);
TaskProva task = new TaskProva();
btnSospendi.addActionListener(e -> task.setSospeso(true));
btnRiprendi.addActionListener(e -> task.setSospeso(false));
task.execute();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new FrameProva().setVisible(true));
}
}
class TaskProva extends SwingWorker<Void, Void> {
private final Object lockSospeso = new Object();
private volatile boolean sospeso;
@Override
protected Void doInBackground() throws Exception {
for (int i = 1; i <= 1000; i++) {
checkSospeso();
System.out.println("giro " + i);
Thread.sleep(250);
}
return null;
}
public void setSospeso(boolean sospeso) {
synchronized (lockSospeso) {
this.sospeso = sospeso;
lockSospeso.notify();
}
}
private void checkSospeso() throws InterruptedException {
if (sospeso) {
synchronized (lockSospeso) {
while (sospeso) {
lockSospeso.wait();
}
}
}
}
}
Ci sono diverse cose da notare:
- ho usato un oggetto di lock specifico (
lockSospeso) perché ho visto nel sorgente di SwingWorker che usa già
synchronized (this) per alcune sincronizzazioni interne e quindi ho preferito NON riusare l'oggetto SwingWorker come "lock" anche per la sospensione.
- la variabile booleana
sospeso è
volatile. Questo è importante per il test su
sospeso messo "fuori" dalla sincronizzazione nel checkSospeso() per rendere il check più efficiente.
- il checkSospeso() l'ho messo private, è ad uso "interno" del task che lo deve usare in tutti i punti dove si può/vuole rendere sospendibile il lavoro
Esegui pure il programma e prova i due pulsanti per vedere l'effetto su standard-output.
P.S. ho usato le lambda (Java 8+) solo per brevità, non sono obbligatorie.