백엔드 개발자라면 대답해야 할 100가지 질문

16.데몬 스레드는 무엇인가요?

ignuy 2023. 9. 1.

멀티태스킹 운영체제에서 Daemon이란 “사용자가 직접 제어하지 않고, 백그라운드에서 돌면서 여러 작업을 수행하는 프로그램”을 의미한다. 일반적으로 윈도우의 서비스나 네트워크 서비스 등을 처리하는 프로그램으로 이해할 수 있다.

🤔여담으로 Daemon의 유래는 과거 MAC 개발자들이 맥스웰의 도깨비 사고 실험(보이지 않는 곳에서 스스로 분자를 골라내는 일을 하는 도깨비)에서 영감을 얻어 도깨비, 악마라는 뜻의 Daemon을 사용했고, 유닉스 시스템이 이 용어를 채용하면서 굳어졌다 한다.

자바의 데몬 스레드

자바의 데몬 스레드도 위 설명과 유사하게 제어 없이도 백그라운드에서 동작하며 애플리케이션(Normal Thread)을 보조하는 역할을 수행하는 스레드이다.

JVM이 가질 수 있는 쓰레드의 종류는 크게 Normal과 Daemon, 이 두 가지로 나뉜다. 원칙적으로 새로 생성되는 스레드는 무조건 부모 스레드의 속성을 상속받는다.

일반 스레드

JVM이 실행되면서 생성되는 일반 스레드에서는 애플리케이션의 기능 로직들이 실행되고 그 자식 스레드들은 모두 항상 일반 스레드의 속성을 상속받은 채로 생성된다.

데몬 스레드

데몬 스레드들은 애플리케이션의 메인 로직을 담고 있지 않고 일반 스레드의 작업을 돕는 보조적인 역할을 수행한다. 대표적인 예를 들자면, 데몬 스레드에서 JVM에 생성된 객체의 메모리 공간을 회수하는 GC(Garbage Collection)을 수행하게 된다.

또한, 데몬 스레드는 일반 스레드의 동작을 보조하는 역할을 하기 때문에 메인 스레드까지 종료된다면 데몬 스레드는 강제로 종료된다. 더 자세히 설명하자면, 메인 스레드가 종료되었을 때 JVM 프로세스가 종료되게 되는데 이때, JVM은 데몬 스레드의 종료를 기다리지 않는다. 만약 JVM이 종료되는 시점에 데몬 스레드가 동작하고 있다 하더라도 스레드를 그냥 종료시키고 셧다운 작업을 수행하게 된다. ← 이 과정을 자세히 생각한다면, 프로세스 종료 시 반드시 수행되는 작업은 데몬 스레드에 위치해서는 안된다는 것을 알 수 있다.

데몬 스레드 실습

앞서 설명했듯이 새로 생성되는 스레드는 원칙적으로 부모 스레드의 속성을 그대로 상속받는다. 만약 일반 스레드에서 데몬 스레드를 생성하거나 데몬 스레드에서 일반 스레드를 생성하기 위해서는 setDaemon(boolean status) 메소드를 사용해야 한다.

public class TestDaemonThread extends Thread {

	public static void main(String[] args) {
	
        TestDaemonThread t1 = new TestDaemonThread();
        TestDaemonThread t2 = new TestDaemonThread();

        // t1을 데몬으로 설정
        t1.setDaemon(true);

        // 스레드 시작
        t1.start();
        t2.start();
    }
	
    public void run() {
        // 데몬 스레드인지 확인
        if(Thread.currentThread().isDaemon()) {
                System.out.println("Daemon thread");
        } else {
                System.out.println("Normal thread executing");
        }
    }
}

/** 출력 형태
 * Daemon thread
 * Normal thread executing
 */

메인스레드가 종료된다면 데몬 스레드의 실행 및 종료 여부에 상관없이 JVM이 데몬스레드를 셧다운 시키는 것을 확인해 보자. 데몬 스레드의 실행을 100ms 지연되도록 설정하여 실행하였다.

public class TestDaemonThread extends Thread {

    public static void main(String[] args) {
        TestDaemonThread t1 = new TestDaemonThread();
        TestDaemonThread t2 = new TestDaemonThread();

        // t1을 데몬으로 설정
        t1.setDaemon(true);

        // 스레드 시작
        t1.start();
        t2.start();
    }
	
	public void run() {
        // 데몬 스레드인지 확인
        if(Thread.currentThread().isDaemon()) {
            while(true) {
                try {
                    Thread.sleep(100L);
                    System.out.println("Daemon thread running");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } else {
            System.out.println("Normal thread executing");
        }
    }
}

/** 출력 형태
 * Normal thread executing
 */

스레드가 실행된 이후에 데몬 스레드로 변경을 시도하게 되면 IllegalThreadStateException이 발생한다.

public class TestDaemonThread extends Thread {

    public static void main(String[] args) {

        TestDaemonThread t1 = new TestDaemonThread();

        // 스레드 시작
        t1.start();

        // t1을 데몬으로 설정
        t1.setDaemon(true);
    }

    public void run() {
        System.out.println("Thread is running");
    }
}

/**
 * Thread is running
 * Exception in thread "main" java.lang.IllegalThreadStateException
 *     at java.lang.Thread.setDaemon(Thread.java:1359)
 *     at TestDaemonThread.main(TestDaemonThread.java:13)
 */

댓글