Post

Virtual Threads In Kotlin

  1. Spring Boot 설정:

application.yml 또는 application.properties에서 가상 스레드를 활성화합니다:

1
2
3
4
spring:
  threads:
    virtual:
      enabled: true
  1. 가상 스레드 설정:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.task.AsyncTaskExecutor
import org.springframework.core.task.support.TaskExecutorAdapter
import java.util.concurrent.Executors

@Configuration
class ThreadConfig {

    @Bean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)
    fun asyncTaskExecutor(): AsyncTaskExecutor {
        return TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor())
    }

    @Bean
    fun protocolHandlerVirtualThreadExecutorCustomizer(): TomcatProtocolHandlerCustomizer<*> {
        return TomcatProtocolHandlerCustomizer { protocolHandler ->
            protocolHandler.executor = Executors.newVirtualThreadPerTaskExecutor()
        }
    }
}
  1. 코루틴 디스패처 설정:

가상 스레드를 사용하는 코루틴 디스패처를 생성합니다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import kotlinx.coroutines.asCoroutineDispatcher
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.util.concurrent.Executors
import kotlin.coroutines.CoroutineContext

@Configuration
class CoroutineConfig {

    @Bean
    fun virtualThreadCoroutineDispatcher(): CoroutineContext {
        return Executors.newVirtualThreadPerTaskExecutor().asCoroutineDispatcher()
    }
}
  1. 코루틴 사용:

이제 코루틴에서 가상 스레드 디스패처를 선택적으로 사용할 수 있습니다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import kotlinx.coroutines.withContext
import org.springframework.stereotype.Service
import org.springframework.beans.factory.annotation.Autowired
import kotlin.coroutines.CoroutineContext

@Service
class MyService(@Autowired private val virtualThreadDispatcher: CoroutineContext) {

    suspend fun someCoroutineFunction() {
        // 기본 코루틴 실행 (스프링의 기본 스레드 풀 사용)
        // ...

        // 가상 스레드에서 실행하고 싶은 부분
        withContext(virtualThreadDispatcher) {
            // 이 블록은 가상 스레드에서 실행됩니다
        }
    }
}
  1. 스프링의 @Async 메서드:

@Async 어노테이션을 사용하는 메서드는 자동으로 가상 스레드 풀을 사용하게 됩니다 (위의 ThreadConfig 설정으로 인해).

1
2
3
4
5
6
7
8
9
10
import org.springframework.scheduling.annotation.Async

@Service
class AsyncService {

    @Async
    fun asyncMethod() {
        // 이 메서드는 가상 스레드에서 실행됩니다
    }
}
  1. 코루틴 스코프 설정 (선택적):

애플리케이션 전체에서 사용할 코루틴 스코프를 정의할 수 있습니다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import kotlin.coroutines.CoroutineContext

@Configuration
class CoroutineScopeConfig {

    @Bean
    fun applicationScope(virtualThreadDispatcher: CoroutineContext): CoroutineScope {
        return CoroutineScope(virtualThreadDispatcher + SupervisorJob())
    }
}

이렇게 설정하면, Spring Boot 애플리케이션에서 가상 스레드와 코루틴을 함께 사용할 수 있습니다. Spring의 기본 비동기 작업은 가상 스레드를 사용하게 되고, 코루틴은 필요에 따라 가상 스레드 디스패처를 선택적으로 사용할 수 있습니다.

주의사항:

  • 모든 작업에 가상 스레드를 사용하는 것이 항상 최선은 아닙니다. 작업의 특성에 따라 적절한 디스패처를 선택해야 합니다.
  • 가상 스레드와 코루틴을 함께 사용할 때는 성능 테스트를 통해 실제 이점을 검증해야 합니다.
  • 일부 라이브러리나 프레임워크는 가상 스레드와 완전히 호환되지 않을 수 있으므로, 철저한 테스트가 필요합니다.

이러한 설정을 통해 가상 스레드의 효율성과 코루틴의 유연성을 모두 활용할 수 있습니다.

This post is licensed under CC BY 4.0 by the author.