Computer >> 컴퓨터 >  >> 프로그래밍 >> Java

Java invokeLater() 메소드 완벽 가이드: AWT 이벤트 디스패치 스레드에서 비동기 작업 실행하기

invokeLater() 메소드는 SwingUtilities 클래스의 정적(static) 메소드로, AWT 이벤트 디스패치 스레드(Event Dispatch Thread, EDT)에서 작업을 비동기적으로(asynchronously) 수행할 때 사용됩니다.

invokeLater()의 동작 원리

SwingUtilities.invokeLater() 메소드는 SwingUtilities.invokeAndWait()와 유사하게 동작하지만, 한 가지 중요한 차이점이 있습니다. invokeLater()는 요청을 이벤트 큐(event queue)에 넣은 후 즉시 반환(immediately returns)합니다. 즉, target으로 전달된 Runnable 객체 내부의 코드 블록이 실행될 때까지 기다리지 않고 다음 코드로 진행합니다.

반면 invokeAndWait()는 Runnable의 실행이 완료될 때까지 호출한 스레드가 대기한다는 점에서 서로 다릅니다. 따라서 UI 업데이트 결과가 필요 없는 경우에는 invokeLater()를 사용하는 것이 프로그램 응답성 측면에서 더 유리합니다.

구문(Syntax)

public static void invokeLater(Runnable target)
  • target: 이벤트 디스패치 스레드에서 실행할 run() 메소드를 가진 Runnable 객체입니다.

예제(Example)

아래 예제는 메인 스레드에서 5초간 대기한 후, invokeLater()를 호출하여 이벤트 스레드에서 JLabel의 텍스트를 변경하는 과정을 보여줍니다.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class InvokeLaterTest extends Object {
    private static void print(String msg) {
        String name = Thread.currentThread().getName();
        System.out.println(name + ": " + msg);
    }

    public static void main(String[] args) {
        final JLabel label = new JLabel("Initial text");
        JPanel panel = new JPanel(new FlowLayout());
        panel.add(label);
        JFrame f = new JFrame("InvokeLater Test");
        f.setContentPane(panel);
        f.setSize(400, 300);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        try {
            print("sleeping for 5 seconds");
            Thread.sleep(5000);
        } catch(InterruptedException ie) {
            print("interrupted while sleeping");
        }
        print("creating the code block for an event thread");
        Runnable setTextRun = new Runnable() {
            public void run() {
                try {
                    Thread.sleep(100);
                    print("about to do setText()");
                    label.setText("New text");
                } catch(Exception e) {
                    e.printStackTrace();
                }
            }
        };
        print("about to call invokeLater()");
        SwingUtilities.invokeLater(setTextRun);
        print("back from invokeLater()");
    }
}

실행 결과(Output)

main: sleeping for 5 seconds
main: creating the code block for an event thread
main: about to call invokeLater()
main: back from invokeLater()
AWT-EventQueue-0: about to do setText()

결과 분석

실행 결과를 보면 흥미로운 점을 확인할 수 있습니다. "back from invokeLater()" 메시지가 먼저 출력되고, 그 이후에 AWT-EventQueue-0 스레드에서 "about to do setText()" 메시지가 출력됩니다.

이것은 invokeLater()가 Runnable의 실행 완료를 기다리지 않고 즉시 제어권을 반환했다는 것을 의미합니다. 실제 setText() 작업은 별도의 이벤트 디스패치 스레드(AWT-EventQueue-0)에서 나중에 비동기적으로 처리되며, 화면의 라벨 텍스트가 "Initial text"에서 "New text"로 변경됩니다.

정리

  • invokeLater()는 Swing 컴포넌트를 안전하게 업데이트하기 위한 표준 방식입니다.
  • 요청을 이벤트 큐에 등록한 후 즉시 반환하므로 호출 스레드가 차단(blocking)되지 않습니다.
  • Runnable의 실행 결과가 반드시 필요한 경우에만 invokeAndWait()를 사용하고, 그 외에는 invokeLater()를 사용하는 것이 좋습니다.
  • 모든 Swing 관련 UI 작업은 이벤트 디스패치 스레드에서 수행해야 스레드 안전성을 보장할 수 있습니다.