Java로 데스크톱 애플리케이션을 개발하다 보면 시간이 오래 걸리는 작업을 처리해야 할 때가 많습니다. 이때 SwingWorker 클래스가 핵심적인 역할을 합니다. SwingWorker는 워커 스레드(worker thread)에서 비동기 작업(예: 장시간 실행되는 작업)을 수행하고, 그 결과를 바탕으로 이벤트 디스패치 스레드(Event Dispatch Thread, EDT)에서 Swing 컴포넌트를 안전하게 업데이트할 수 있도록 지원합니다. 이 클래스는 Java 1.6 버전부터 도입되었습니다.
SwingWorker 클래스란?
javax.swing.SwingWorker 클래스는 백그라운드에서 시간이 오래 걸리는 작업을 수행하는 태스크 워커(task worker)입니다. Swing은 기본적으로 단일 스레드 모델을 사용하기 때문에, EDT에서 무거운 작업을 직접 실행하면 UI가 멈추는 현상(freeze)이 발생합니다. SwingWorker는 이러한 문제를 우아하게 해결해 줍니다.
SwingWorker와 상호작용하는 3개의 스레드
SwingWorker 인스턴스는 다음 세 가지 스레드와 상호작용합니다.
- 현재 스레드(Current thread):
execute()메서드를 호출하여 작업을 백그라운드로 넘긴 후 즉시 반환됩니다. - 워커 스레드(Worker thread): 개발자가 재정의한
doInBackground()메서드를 백그라운드에서 계속 실행합니다. - 이벤트 디스패치 스레드(EDT): 주기적으로 깨어나 워커 스레드에서 발생한 변경 사항을 알려줍니다.
주요 메서드와 동작 방식
- doInBackground() 종료 시: 작업이 끝나면 EDT가 개발자가 재정의한
done()메서드를 호출하여 결과를 알려줍니다. - 중간 값 게시:
doInBackground()내부에서publish(V)메서드를 호출하면, EDT가process(List)메서드를 통해 중간 결과를 전달합니다. - 진행률 업데이트:
doInBackground()에서setProgress(i)메서드를 호출하면, EDT가PropertyChangeListener를 통해 진행 상태 변화를 통지합니다. - JProgressBar 연동:
javax.swing.JProgressBar클래스는 SwingWorker 인스턴스로 구현된 백그라운드 작업의 진행 상황을 화면에 표시하도록 설계된 UI 컴포넌트입니다.
예제 코드
다음 예제는 버튼 클릭 시 SwingWorker를 실행하여 10초간의 작업을 백그라운드에서 처리하고, 완료 후 다이얼로그의 내용을 갱신하는 코드입니다.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SwingWorkerTest {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
JButton button = new JButton();
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new GUIWorker().execute();
}
});
button.setText("Click Me !!!");
frame.getContentPane().add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setSize(350, 300);
frame.setVisible(true);
}
});
}
}
class GUIWorker extends SwingWorker {
private JFrame frame = new JFrame();
private JDialog dialog = new JDialog(frame, "Swingworker Test", true);
private JProgressBar progressBar = new JProgressBar();
public GUIWorker() {
progressBar.setString("Waiting on time");
progressBar.setStringPainted(true);
progressBar.setIndeterminate(true);
dialog.getContentPane().add(progressBar);
dialog.setSize(350, 300);
dialog.setModal(false);
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
}
@Override
protected Integer doInBackground() throws Exception {
System.out.println("GUIWorker doInBackground()");
Thread.sleep(10000);
return 0;
}
@Override
protected void done() {
System.out.println("done");
JLabel label = new JLabel("Task Complete");
dialog.getContentPane().remove(progressBar);
dialog.getContentPane().add(label);
dialog.getContentPane().validate();
}
}실행 결과
버튼을 클릭하면 불확정(indeterminate) 모드의 진행 표시줄이 담긴 다이얼로그가 나타나고, 백그라운드 작업이 10초간 진행됩니다. 작업이 완료되면 done() 메서드가 EDT에서 호출되어 진행 표시줄이 제거되고 "Task Complete" 라벨로 교체됩니다. 이 과정 동안 메인 프레임의 UI는 멈추지 않고 정상적으로 반응합니다.
마무리
SwingWorker는 Swing 애플리케이션에서 응답성 있는 UI를 유지하면서 무거운 작업을 처리할 수 있게 해주는 필수 도구입니다. doInBackground(), done(), publish(), process() 등의 메서드를 적절히 활용하면 스레드 관련 복잡한 코드 없이도 안전하고 깔끔한 비동기 처리를 구현할 수 있습니다.