생계유지형 개발자/Reactive Programming

[리액티브 프로그래밍] User Thread, Daemon Thread의 차이점

이 가을 2021. 3. 16. 17:34

사용자 쓰레드(User Thread)와 대몬 쓰레드(Daemon)

사용자 쓰레드와 대몬 쓰레드의 차이점은 메인 쓰레드(Main Thread)가 종료되었을 때 함께 종료되는가, 그렇지 않은가에 있다.

사용자 쓰레드는 메인 쓰레드가 종료되어도 프로세스를 강제로 종료하지 않는다. (종료하는 주체는 JVM이다.)

반면에 대몬 쓰레드는 메인 쓰레드 또는 남겨진 사용자 쓰레드가 종료되면 강제로 프로세스가 종료된다.

 

아래 예제 소스코드에서 Reactor라이브러리에서 제공하는 Flux 클래스의 Flux.interval() 함수와 단일 쓰레드를 생성하는 Executors.newSingleThreadExecutor() 함수가 정의되어 있다.

Flux.interval() 함수는 내부적으로 대몬 쓰레드를 생성하여 로직을 실행한다.

Executors.newSingleThreadExecutor().execute() 함수는 사용자 쓰레드를 생성하여 로직을 실행한다. 

package toby

import reactor.core.publisher.Flux
import java.time.Duration
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit

/**
 *
 *
 * @author Lee Gaeul <gaeul.lee@navercorp.com>
 * @since 2021. 03. 16
 */

fun main(args: Array<String>) {
    // Flux.interval()는 Daemon Thread 생성
    Flux.interval(Duration.ofMillis(500))
        .take(20)   // 데이터를 20개 수신하면 종료됨
        .subscribe { log("Data: $it") }  // 0.5초마다 0부터 20까지 1씩 증가하는 데이터 출력
    }

    // Executor는 User Thread 생성
    val executors = Executors.newSingleThreadExecutor()
    executors.execute {
        log("A single thread has been executed. ")
        try {
            TimeUnit.SECONDS.sleep(5) // 5초간 Thread sleep
            log("It's been 5 seconds. ")

        } catch (e: InterruptedException) {}

    }
    
    executors.shutdown()
    log("Hello Flux :)")
}

// Console 출력 함수 => [Thread명] - 출력메세지 형태로 출력된다.
private fun log(text: String) {
    val currentThread: String = Thread.currentThread().name
    println("[$currentThread] - $text")
}

코드를 실행하면 콘솔에 출력된 결과는 다음과 같다. (앞에 쓰레드 명이 다른 것을 주목하자.)

 

[main] - Hello Flux :)
[pool-2-thread-1] - A single thread has been executed. 
[parallel-1] - Data: 0
[parallel-1] - Data: 1
[parallel-1] - Data: 2
[parallel-1] - Data: 3
[parallel-1] - Data: 4
[parallel-1] - Data: 5
[parallel-1] - Data: 6
[parallel-1] - Data: 7
[parallel-1] - Data: 8
[pool-2-thread-1] - It's been 5 seconds.
[parallel-1] - Data: 9

 

Process finished with exit code 0

 

--- 해석 --- 

 

1. 메인 쓰레드는 Flux와 Executors에서 각각 생성한 쓰레드의 작업 처리 완료를 기다리지 않고 "Hello Flux :)" 메세지를 출력한 뒤 종료된다.

메인 쓰레드가 종료되면 원래는 Flux 로직(대몬 쓰레드)가 종료되어야 하는데 Executors 로직(사용자 쓰레드)에서 5초 동안 Sleep하여 종료되지 않았다.

 

2. Flux 로직(대몬 쓰레드)이 먼저 실행되었지만 0.5초 뒤에 처음 출력되므로, Executors 로직(사용자 쓰레드)이 먼저 "A single thread has been executed."를 출력한다. 

 

3. executors.shutdown()를 호출함으로써 사용자 쓰레드가 종료되기 전 까지 대몬 쓰레드는 0.5초마다 "Data"를 출력한다.

 

4. 5초 후 대몬 쓰레드가 종료되면 남아있는 쓰레드가 없기 때문에 대몬 쓰레드는 20까지 출력하지 못하고 종료된다.  

 

 

참고

www.youtube.com/watch?v=Wlqu1xvZCak&t=3559s