[Kotlin] ์ฝ”๋ฃจํ‹ด: ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์‹œ์Šคํ…œ

2025. 2. 27. 15:22ยทLanguages/Kotlin

์„ฌ๋„ค์ผ.jpg

Kotlin์˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜

์ตœ์‹  ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ฑ๋Šฅ ์ตœ์ ํ™”์˜ ํ•ต์‹ฌ ์š”์†Œ๋กœ ์ž๋ฆฌ ์žก์•˜์Šต๋‹ˆ๋‹ค. ํŠนํžˆ Kotlin์€ ์ฝ”๋ฃจํ‹ด(coroutine)์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ๊ฐ•๋ ฅํ•œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์‹œ์Šคํ…œ์„ ์ œ๊ณตํ•˜๋ฉฐ, ์ด๋Š” ๊ธฐ์กด์˜ ์ฝœ๋ฐฑ ์ง€์˜ฅ(callback hell) ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ์ง๊ด€์ ์ธ ์ฝ”๋“œ ์ž‘์„ฑ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ๋ณธ ๋ณด๊ณ ์„œ์—์„œ๋Š” Kotlin์˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์‹ฌ์ธต ๋ถ„์„ํ•˜๊ณ , runBlocking, Dispatchers.IO, Promise ๊ฐœ๋…์˜ ์ฐจ์ด์ ๊ณผ ์‹ค์ œ ์ ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๊ตฌ์ฒด์ ์ธ ์ฝ”๋“œ ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.


1. Kotlin ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์˜ ํ•ต์‹ฌ ๊ฐœ๋…

1.1 ์ฝ”๋ฃจํ‹ด์˜ ๊ตฌ์กฐ์  ๋™์‹œ์„ฑ

Kotlin ์ฝ”๋ฃจํ‹ด์€ ๊ฒฝ๋Ÿ‰ ์Šค๋ ˆ๋“œ(lightweight thread) ๊ฐœ๋…์„ ๊ตฌํ˜„ํ•˜์—ฌ ๊ธฐ์กด Java ์Šค๋ ˆ๋“œ๋ณด๋‹ค 100๋ฐฐ ์ด์ƒ ๊ฐ€๋ฒผ์šด ์‹คํ–‰ ๋‹จ์œ„๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ตฌ์กฐ์  ๋™์‹œ์„ฑ(structured concurrency) ์›์น™์— ๋”ฐ๋ผ ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๋ฅผ ํ˜•์„ฑํ•˜๋ฉฐ, ์ด๋Š” ๋ฆฌ์†Œ์Šค ๋ˆ„์ˆ˜ ๋ฐฉ์ง€์™€ ์˜ˆ์™ธ ์ „ํŒŒ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch { // ๋ถ€๋ชจ ์ฝ”๋ฃจํ‹ด
        launch { // ์ž์‹ ์ฝ”๋ฃจํ‹ด 1
            delay(1000L)
            println("์ฒซ ๋ฒˆ์งธ ์ž‘์—… ์™„๋ฃŒ")
        }
        launch { // ์ž์‹ ์ฝ”๋ฃจํ‹ด 2
            delay(1500L)
            println("๋‘ ๋ฒˆ์งธ ์ž‘์—… ์™„๋ฃŒ")
        }
    }
    job.join() // ๋ชจ๋“  ์ž์‹ ์ฝ”๋ฃจํ‹ด ์™„๋ฃŒ ๋Œ€๊ธฐ
}

1.2 ์ค‘๋‹จ ํ•จ์ˆ˜(Suspend Function)์˜ ๋™์ž‘ ์›๋ฆฌ

suspend ํ‚ค์›Œ๋“œ๋กœ ํ‘œ์‹œ๋œ ํ•จ์ˆ˜๋Š” ์ฝ”๋ฃจํ‹ด ๋‚ด์—์„œ๋งŒ ํ˜ธ์ถœ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ์‹คํ–‰ ์ค‘๋‹จ๊ณผ ์žฌ๊ฐœ๋ฅผ ํ†ตํ•ด ๋น„์ฐจ๋‹จ(non-blocking) ๋™์ž‘์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๋Š” CPS(Continuation-Passing Style) ๋ณ€ํ™˜์„ ํ†ตํ•ด ์ค‘๋‹จ ์ง€์ (suspension point)์„ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

suspend fun fetchUserData(userId: String): User {
    return withContext(Dispatchers.IO) {
        // ๋„คํŠธ์›Œํฌ ์š”์ฒญ ์‹œ๋ฎฌ๋ ˆ์ด์…˜
        delay(2000L)
        User(userId, "ํ™๊ธธ๋™")
    }
}

2. ์ฃผ์š” ๋น„๋™๊ธฐ ๊ตฌ์„ฑ ์š”์†Œ ์‹ฌ์ธต ๋ถ„์„

2.1 runBlocking: ๋™๊ธฐ-๋น„๋™๊ธฐ ๋ธŒ๋ฆฟ์ง€

runBlocking์€ ์ฝ”๋ฃจํ‹ด ์„ธ๊ณ„์™€ ์ผ๋ฐ˜ ๋ธ”๋กœํ‚น ์ฝ”๋“œ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ํŠน์ˆ˜ํ•œ ์ฝ”๋ฃจํ‹ด ๋นŒ๋”์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ ์Šค๋ ˆ๋“œ๋ฅผ ์ฐจ๋‹จํ•˜๋ฉฐ ๋‚ด๋ถ€ ์ฝ”๋ฃจํ‹ด ์‹คํ–‰์„ ์™„๋ฃŒํ•  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐํ•ฉ๋‹ˆ๋‹ค.

ํŠน์ง•:

  • ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์ด๋‚˜ ๋ฉ”์ธ ํ•จ์ˆ˜์—์„œ ์ œํ•œ์  ์‚ฌ์šฉ
  • Android ๋ฉ”์ธ ์Šค๋ ˆ๋“œ ์‚ฌ์šฉ ์‹œ ๋ฐ๋“œ๋ฝ ์œ„ํ—˜
  • ๋””์ŠคํŒจ์ฒ˜ ์ง€์ • ์‹œ ์ด๋ฒคํŠธ ๋ฃจํ”„ ์ถฉ๋Œ ๊ฐ€๋Šฅ์„ฑ
fun main() {
    runBlocking {
        launch {
            delay(1000L)
            println("runBlocking ๋‚ด๋ถ€ ์‹คํ–‰")
        }
    }
    println("runBlocking ์ข…๋ฃŒ ํ›„ ์‹คํ–‰") // ๋ธ”๋ก ์™„๋ฃŒ ํ›„ ์‹คํ–‰
}

2.2 Dispatchers.IO vs Dispatchers.Default

Kotlin์€ ์ž‘์—… ์œ ํ˜•์— ์ตœ์ ํ™”๋œ ๋””์ŠคํŒจ์ฒ˜๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, CPU ์ง‘์•ฝ์  ์ž‘์—…๊ณผ I/O ์ž‘์—…์„ ๋ช…ํ™•ํžˆ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

ํŠน์„ฑ Dispatchers.Default Dispatchers.IO
๋ชฉ์  CPU ์ง‘์•ฝ์  ์—ฐ์‚ฐ(์ •๋ ฌ, ๋ณต์žกํ•œ ๊ณ„์‚ฐ) ํŒŒ์ผ I/O, ๋„คํŠธ์›Œํฌ ์š”์ฒญ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘๊ทผ
์Šค๋ ˆ๋“œ ํ’€ ํฌ๊ธฐ CPU ์ฝ”์–ด ์ˆ˜ (์ตœ์†Œ 2) ์ตœ๋Œ€ 64๊ฐœ
์‚ฌ์šฉ ์‚ฌ๋ก€ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ, ๋จธ์‹ ๋Ÿฌ๋‹ ๋ชจ๋ธ ์‹คํ–‰ REST API ํ˜ธ์ถœ, ๋กœ์ปฌ DB ์ฟผ๋ฆฌ
๋ฆฌ์†Œ์Šค ๊ณต์œ  ์ฝ”์–ด๋‹น ์ „์šฉ ์Šค๋ ˆ๋“œ Default์™€ ์Šค๋ ˆ๋“œ ํ’€ ๊ณต์œ 
// CPU ์ง‘์•ฝ์  ์ž‘์—… ์˜ˆ์ œ
fun calculateFibonacci(n: Int) = runBlocking {
    withContext(Dispatchers.Default) {
        // ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜ ๊ณ„์‚ฐ
    }
}

// I/O ์ž‘์—… ์˜ˆ์ œ
suspend fun loadFileContent(path: String) = 
    withContext(Dispatchers.IO) {
        File(path).readText()
    }

2.3 Deferred(Promise ํŒจํ„ด ๊ตฌํ˜„์ฒด)

Kotlin์˜ Deferred๋Š” JavaScript์˜ Promise์™€ ์œ ์‚ฌํ•œ ๊ฐœ๋…์œผ๋กœ, ๋น„๋™๊ธฐ ์—ฐ์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ์บก์Аํ™”ํ•ฉ๋‹ˆ๋‹ค. async ๋นŒ๋”๋กœ ์ƒ์„ฑ๋˜๋ฉฐ await()์„ ํ†ตํ•ด ๊ฒฐ๊ณผ๋ฅผ ํš๋“ํ•ฉ๋‹ˆ๋‹ค.

suspend fun fetchMultipleData() = coroutineScope {
    val userDeferred = async { getUserData() }
    val productDeferred = async { getProductList() }

    val user = userDeferred.await() // ๊ฒฐ๊ณผ ๋Œ€๊ธฐ
    val products = productDeferred.await()
    combineData(user, products)
}

JavaScript Promise์™€์˜ ์ฃผ์š” ์ฐจ์ด์ :

  • ๋ช…์‹œ์  ์ค‘๋‹จ(resume) ๋ฉ”์ปค๋‹ˆ์ฆ˜
  • ๊ตฌ์กฐ์  ๋™์‹œ์„ฑ ์ง€์›
  • ์ทจ์†Œ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๋‚ด์žฅ

3. ๊ตฌ์„ฑ ์š”์†Œ ๊ฐ„ ์ƒํ˜ธ์ž‘์šฉ ๋ฐ ์„ฑ๋Šฅ ๋น„๊ต

3.1 ์‹คํ–‰ ์ปจํ…์ŠคํŠธ ๊ตํ™˜ ์ „๋žต

fun complexWorkflow() = runBlocking {
    val result = withContext(Dispatchers.Default) {
        // CPU ์ง‘์•ฝ์  ์ž‘์—…
        val processed = processData()
        withContext(Dispatchers.IO) {
            // ๊ฒฐ๊ณผ ์ €์žฅ
            saveToDatabase(processed)
        }
    }
    updateUI(result)
}

3.2 ์„ฑ๋Šฅ ๋ฒค์น˜๋งˆํฌ (๊ฐ€์ƒ ๋ฐ์ดํ„ฐ)

์‹œ๋‚˜๋ฆฌ์˜ค runBlocking Dispatchers.IO Dispatchers.Default
10,000๊ฐœ ํŒŒ์ผ ์ฒ˜๋ฆฌ 12,450ms 8,230ms 15,670ms
๋Œ€์šฉ๋Ÿ‰ JSON ํŒŒ์‹ฑ 6,780ms 7,890ms 3,210ms
๋™์‹œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ 100ํšŒ 9,870ms 4,560ms 10,340ms

4. ์‹ค์ „ ์ ์šฉ ํŒจํ„ด ๋ฐ ์ตœ์ ํ™” ๊ธฐ๋ฒ•

4.1 ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ์ตœ์ ํ™”

suspend fun parallelProcessing() = coroutineScope {
    val deferredList = (1..1000).map {
        async(Dispatchers.Default) {
            processItem(it)
        }
    }
    deferredList.awaitAll()
}

4.2 ๋””์ŠคํŒจ์ฒ˜ ํ˜ผํ•ฉ ์‚ฌ์šฉ ์‚ฌ๋ก€

fun optimizedFileProcessor() = runBlocking {
    val ioDispatcher = Dispatchers.IO.limitedParallelism(32)
    val cpuDispatcher = Dispatchers.Default

    launch(ioDispatcher) {
        val rawData = readLargeFile()
        val processed = withContext(cpuDispatcher) {
            parseData(rawData)
        }
        withContext(ioDispatcher) {
            writeProcessedData(processed)
        }
    }
}

4.3 ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ „๋žต

suspend fun robustNetworkCall() {
    try {
        val response = withContext(Dispatchers.IO) {
            apiClient.getData()
        }
        handleResponse(response)
    } catch (e: IOException) {
        logError("๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜", e)
    } catch (e: CancellationException) {
        throw e // ์ฝ”๋ฃจํ‹ด ์ทจ์†Œ ์˜ˆ์™ธ๋Š” ์ƒ์œ„๋กœ ์ „ํŒŒ
    }
}

5. ๊ตฌ์„ฑ ์š”์†Œ ์„ ํƒ ๊ฐ€์ด๋“œ๋ผ์ธ

5.1 runBlocking ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค

  • ์ ํ•ฉํ•œ ๊ฒฝ์šฐ:
    • JUnit ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค
    • ๋ฉ”์ธ ํ•จ์ˆ˜ ์ง„์ž…์ 
    • ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ ํ†ตํ•ฉ
  • ์ฃผ์˜ ์‚ฌํ•ญ:
    • Android ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ์˜ ์‚ฌ์šฉ ๊ธˆ์ง€
    • ์žฅ์‹œ๊ฐ„ ์‹คํ–‰ ์ž‘์—… ํšŒํ”ผ

5.2 Dispatchers ์„ ํƒ ๋งคํŠธ๋ฆญ์Šค

graph TD
    A[์ž‘์—… ์œ ํ˜•?] --> B{CPU ์ง‘์•ฝ์ }
    B --> |Yes| C[Dispatchers.Default]
    B --> |No| D{์ฐจ๋‹จ ๊ฐ€๋Šฅ์„ฑ}
    D --> |Yes| E[Dispatchers.IO]
    D --> |No| F[Dispatchers.Main/Unconfined]

5.3 Deferred ํ™œ์šฉ ์ „๋žต

  • ์ตœ์  ์‚ฌ์šฉ ์‚ฌ๋ก€:
    • ๋‹ค์ค‘ ๋…๋ฆฝ ์ž‘์—… ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ
    • ์„ ํ–‰ ์ž‘์—… ๊ฒฐ๊ณผ ์˜์กด์„ฑ ๊ด€๋ฆฌ
    • ํƒ€์ž„์•„์›ƒ ์ œ์–ด๊ฐ€ ํ•„์š”ํ•œ ์—ฐ์‚ฐ
  • ์„ฑ๋Šฅ ๊ฐœ์„  ํŒ:
    • awaitAll()์„ ํ†ตํ•œ ์ผ๊ด„ ์ฒ˜๋ฆฌ
    • coroutineScope ๋‚ด์—์„œ์˜ ์ œํ•œ์  ์‚ฌ์šฉ
    • ์ทจ์†Œ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์ ๊ทน ํ™œ์šฉ

6. ๊ณ ๊ธ‰ ์ฃผ์ œ ๋ฐ ์ตœ์‹  ๋™ํ–ฅ

6.1 Kotlin Flow์™€์˜ ํ†ตํ•ฉ

fun observeDataStream() = runBlocking {
    dataSource.getLiveUpdates()
        .flowOn(Dispatchers.IO)
        .map { processRawData(it) }
        .flowOn(Dispatchers.Default)
        .collect { updateUI(it) }
}

6.2 ๋ฉ€ํ‹ฐํ”Œ๋žซํผ ํ™˜๊ฒฝ ๊ณ ๋ ค์‚ฌํ•ญ

  • iOS์˜ DispatchQueue ํ†ตํ•ฉ
  • JavaScript ๋Ÿฐํƒ€์ž„๊ณผ์˜ ์ƒํ˜ธ์šด์šฉ์„ฑ
  • ๋„ค์ดํ‹ฐ๋ธŒ ํ”Œ๋žซํผ๋ณ„ ์Šค๋ ˆ๋”ฉ ์ •์ฑ…

๊ฒฐ๋ก : ์ƒํ™ฉ๋ณ„ ์ตœ์ ์˜ ์ ‘๊ทผ๋ฒ•

Kotlin์˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๋„๊ตฌ๋“ค์€ ๊ฐ๊ธฐ ๋ช…ํ™•ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. runBlocking์€ ํ…Œ์ŠคํŠธ์™€ ํ”„๋กœํ† ํƒ€์ดํ•‘์— ์œ ์šฉํ•˜์ง€๋งŒ ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ์—์„œ๋Š” ์‹ ์ค‘ํ•˜๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Dispatchers.IO๋Š” ํŒŒ์ผ ์ฒ˜๋ฆฌ๋‚˜ ๋„คํŠธ์›Œํฌ ํ†ต์‹  ์‹œ ํ•„์ˆ˜์ ์ด๋ฉฐ, Dispatchers.Default๋Š” ๋ณต์žกํ•œ ๊ณ„์‚ฐ ์ž‘์—…์— ์ตœ์ ํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. Deferred๋Š” JavaScript์˜ Promise ํŒจํ„ด์„ Kotlin ์Šคํƒ€์ผ๋กœ ๊ตฌํ˜„ํ•œ ๊ฒƒ์œผ๋กœ, ๋ณต์žกํ•œ ๋ณ‘๋ ฌ ์ž‘์—… ํ๋ฆ„์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ํƒ์›”ํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ œ ๊ฐœ๋ฐœ ์‹œ ์ž‘์—…์˜ ํŠน์„ฑ์„ ์ •ํ™•ํžˆ ๋ถ„์„ํ•˜๊ณ (CPU-bound vs I/O-bound), ๊ตฌ์กฐ์  ๋™์‹œ์„ฑ ์›์น™์„ ์ค€์ˆ˜ํ•˜๋ฉฐ, Kotlin ์ฝ”๋ฃจํ‹ด์˜ ๊ณ„์ธต์  ์ทจ์†Œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ ๊ทน ํ™œ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ Android ํ™˜๊ฒฝ์—์„œ๋Š” ๋ฉ”์ธ ์Šค๋ ˆ๋“œ ์ฐจ๋‹จ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด Dispatchers.Main๊ณผ์˜ ์กฐํ•ฉ์„ ์‹ ์ค‘ํ•˜๊ฒŒ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์‹  Kotlin ๋ฒ„์ „์—์„œ๋Š” ํ”Œ๋กœ์šฐ(Flow)์™€์˜ ํ†ตํ•ฉ์ด ๋”์šฑ ๊ฐ•ํ™”๋˜์–ด ์žˆ์œผ๋ฉฐ, ์ ์ฐจ RxJava ํŒจํ„ด์„ ๋Œ€์ฒดํ•ด ๋‚˜๊ฐ€๋Š” ์ถ”์„ธ์ž…๋‹ˆ๋‹ค.

728x90
์ €์ž‘์žํ‘œ์‹œ ๋น„์˜๋ฆฌ ๋ณ€๊ฒฝ๊ธˆ์ง€ (์ƒˆ์ฐฝ์—ด๋ฆผ)
'Languages/Kotlin' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • Kotlin 2.1.10 ๋ณ€๊ฒฝ์ 
  • [Kotlin] ํด๋ž˜์Šค ์ ‘๊ทผ ์ œ์–ด์ž์™€ ์ˆ˜์ •์ž(protected, inner, private, open)
  • [Kotlin] class์™€ object ์ฐจ์ด์ 
  • [Kotlin] ์ฝ”ํ‹€๋ฆฐ let, run, apply, also, with์˜ ์ฐจ์ด์™€ ์ ์ ˆํ•œ ์‚ฌ์šฉ ์ƒํ™ฉ ๋ถ„์„
์ง€๋‹ˆ๐Ÿงž‍โ™‚๏ธ๐Ÿฅญ
์ง€๋‹ˆ๐Ÿงž‍โ™‚๏ธ๐Ÿฅญ
์ผ์ƒ, ๊ฒŒ์ž„, ๋ง›์ง‘, ์—ฌํ–‰, ๊ฐœ๋ฐœ, IT ๋ธ”๋กœ๊ทธ๐Ÿงž
  • ์ง€๋‹ˆ๐Ÿงž‍โ™‚๏ธ๐Ÿฅญ
    ์š”์ˆ  ๋žจํ”„๐Ÿซ–
    ์ง€๋‹ˆ๐Ÿงž‍โ™‚๏ธ๐Ÿฅญ
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • All (549)
      • Languages (57)
        • JAVA (13)
        • JSP (1)
        • C_C++ (4)
        • Html (3)
        • CSS (1)
        • JavaScript (18)
        • Python (3)
        • Kotlin (13)
        • TypeScript (1)
      • Framework (14)
        • spring (11)
        • jstl (1)
        • angular (2)
      • Tool (28)
        • Eclipse (5)
        • vsCode (3)
        • scrcpy (2)
        • Git (1)
        • IntelliJ (6)
        • Visual-studio (1)
        • UML (1)
        • Gradle (8)
      • DB (6)
        • Oracle (1)
        • MySql (3)
        • Mongo (2)
      • OS (14)
        • Linux (2)
        • Windows (12)
      • Server (8)
        • Tomcat (1)
        • Apache (1)
        • Node.js (6)
      • Programmings (25)
        • Design Pattern (2)
        • Funny (20)
        • Algorithms (3)
      • Cloud (8)
        • Docker (1)
        • Kubernetes (4)
        • Istio (1)
        • ArgoCD (2)
      • IT (5)
        • gRPC (3)
        • RESTful (3)
        • Web UI (5)
        • AI (4)
      • Book (6)
      • TIP (187)
      • Life (53)
      • Game (83)
      • Storage (22)
      • ์‹๋‹น (15)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
    • ์‚ฌ์ดํŠธ๋งต
    • RSS
    • ๊ธฐํƒ€ ์†Œ๋“
  • ๋งํฌ

    • ๊ตฌ๊ธ€
    • ๋„ค์ด๋ฒ„
    • ์ •๋ถ€24
    • Spring Framework ๋ฆด๋ฆฌ์ฆˆ ๋…ธํŠธ
    • Kotlin ๋ฆด๋ฆฌ์ฆˆ ๋…ธํŠธ
    • ์นด์นด์˜ค ์• ๋“œํ•
    • ๋ธ”๋กœ๊ทธ ์‚ฌ์ดํŠธ๋งต
    • ๋ธ”๋กœ๊ทธ RSS
  • ๊ณต์ง€์‚ฌํ•ญ

    • ์•ˆ๋…•ํ•˜์„ธ์š”
  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    ๋ฐ์ผ๋ฆฌ ๋‰ด์Šค
    ๋ธŒ๋ฆฌํ•‘
    ๋ชฌ์Šคํ„ฐํ—Œํ„ฐ๋‚˜์šฐ
    ๋ชฌ์Šคํ„ฐํ—Œํ„ฐ์™€์ผ์ฆˆ
    ํ€˜์ŠคํŠธ
    ๋‰ด์Šค ๋ธŒ๋ฆฌํ•‘
    ํƒœ๊ตญ
    ์˜ค๋Š˜์˜๋‰ด์Šค
    ๋‰ด์Šค
    ํ•œ๋ˆˆ์— ๋ณด๋Š” ์˜ค๋Š˜์˜ ๋‰ด์Šค
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.3
์ง€๋‹ˆ๐Ÿงž‍โ™‚๏ธ๐Ÿฅญ
[Kotlin] ์ฝ”๋ฃจํ‹ด: ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์‹œ์Šคํ…œ
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”