SwingWorker<T, V> es la solución oficial de Swing para ejecutar trabajo pesado fuera del EDT sin congelar la interfaz. El tipo T es el resultado final y V es el tipo de los datos intermedios publicados durante el progreso.
import javax.swing.*;
import java.util.List;
public class CargaWorker extends SwingWorker<String, Integer> {
private final JProgressBar barra;
private final JLabel estado;
public CargaWorker(JProgressBar barra, JLabel estado) {
this.barra = barra;
this.estado = estado;
}
@Override
protected String doInBackground() throws Exception {
// Se ejecuta en un hilo de fondo (no en el EDT)
for (int i = 0; i <= 100; i += 10) {
Thread.sleep(200); // simula trabajo
publish(i); // envía progreso al EDT
setProgress(i);
}
return "Carga completada";
}
@Override
protected void process(List<Integer> chunks) {
// Se ejecuta en el EDT con los valores publicados
int ultimo = chunks.getLast(); // Java 21: getLast() en List
barra.setValue(ultimo);
}
@Override
protected void done() {
// Se ejecuta en el EDT cuando doInBackground() termina
try {
estado.setText(get()); // obtiene el valor de retorno
} catch (Exception ex) {
estado.setText("Error: " + ex.getMessage());
}
}
}
Usar SwingWorker
JProgressBar barra = new JProgressBar(0, 100);
JLabel estado = new JLabel("Listo");
JButton boton = new JButton("Iniciar");
boton.addActionListener(e -> {
boton.setEnabled(false);
CargaWorker worker = new CargaWorker(barra, estado);
worker.addPropertyChangeListener(evt -> {
if ("state".equals(evt.getPropertyName()) &&
SwingWorker.StateValue.DONE == evt.getNewValue()) {
boton.setEnabled(true);
}
});
worker.execute();
});
Timer: acciones periódicas en el EDT
javax.swing.Timer ejecuta una acción repetidamente en el EDT, ideal para animaciones, reloj en pantalla o actualización periódica de datos:
JLabel reloj = new JLabel();
Timer timer = new Timer(1000, e -> {
reloj.setText(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
});
timer.setInitialDelay(0);
timer.start();
// Detener cuando se cierre la ventana
frame.addWindowListener(new WindowAdapter() {
@Override public void windowClosing(WindowEvent e) { timer.stop(); }
});
Virtual Threads y Swing (Java 21)
Java 21 introduce los Virtual Threads (Thread.ofVirtual()), que son ligeros y no bloquean el hilo del OS. Aunque no reemplazan a SwingWorker para actualizaciones de UI, simplifican el lanzamiento de tareas en segundo plano:
boton.addActionListener(e -> {
Thread.ofVirtual().start(() -> {
String resultado = servicioLento.obtenerDatos(); // en virtual thread
SwingUtilities.invokeLater(() -> campo.setText(resultado)); // vuelta al EDT
});
});
