0Pricing
Kotlin Academy · 강의

공유 상태를 위한 Mutex와 Semaphore

Mutex로 공유 변경 가능 상태를 보호하고 Semaphore로 동시 실행을 제한해 보세요.

공유 상태를 위한 Mutex와 Semaphore은(는) CoddyKit의 무료 Kotlin Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Kotlin Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

공유 상태 문제

여러 스레드에서 실행되는 코루틴은 공유된 변경 가능 상태를 손상시킬 수 있습니다. 동기화하지 않으면 동시에 증가시키는 작업에서 잘못된 결과가 나옵니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    var counter = 0
    val jobs = List(1000) {
        launch(Dispatchers.Default) { counter++ } // race condition!
    }
    jobs.forEach { it.join() }
    println("Expected 1000, got: $counter") // likely wrong
}

뮤텍스 기초

Mutex는 코루틴을 위한 상호 배제 잠금입니다. 잠금을 사용할 수 있을 때까지 호출자를 차단하지 않고 일시 중단합니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
fun main() = runBlocking {
    val mutex = Mutex()
    var counter = 0
    val jobs = List(1000) {
        launch(Dispatchers.Default) {
            mutex.withLock { counter++ }  // safe
        }
    }
    jobs.forEach { it.join() }
    println("Counter: $counter") // 1000
}

withLock 확장

mutex.withLock { ... }은 잠금을 획득하고 블록을 실행한 뒤 잠금을 해제합니다. 예외나 취소가 발생한 경우에도 잠금을 해제합니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
fun main() = runBlocking {
    val mutex = Mutex()
    var list = mutableListOf<Int>()
    List(10) {
        launch {
            mutex.withLock {
                list.add(it)
            }
        }
    }.forEach { it.join() }
    println(list.sorted())
}

lock / unlock 수동 사용하기

더 세밀하게 제어하려면 lock()과 unlock()을 직접 호출할 수 있지만, 잠금 해제를 잊지 않도록 withLock을 우선 사용하십시오.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
fun main() = runBlocking {
    val mutex = Mutex()
    mutex.lock()
    try {
        println("Critical section")
    } finally {
        mutex.unlock()  // must always release
    }
}

Mutex는 재진입 가능하지 않음

코틀린의 Mutex는 재진입 가능하지 않습니다. 같은 코루틴에서 lock()을 다시 호출하면 교착 상태가 발생합니다. 중첩 잠금을 피하려면 카운터를 사용하거나 구조를 변경하십시오.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
fun main() = runBlocking {
    val mutex = Mutex()
    // This deadlocks:
    // mutex.withLock { mutex.withLock { println("never") } }
    mutex.withLock {
        println("Acquired once — safe")
    }
}

세마포어 기초

Semaphore(n)은 최대 n개의 코루틴이 동시에 진행하도록 허용합니다. n개의 자리가 있는 티켓 시스템과 같습니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
fun main() = runBlocking {
    val semaphore = Semaphore(3) // max 3 concurrent
    List(10) { i ->
        launch {
            semaphore.withPermit {
                println("Concurrent task $i"); delay(100)
            }
        }
    }.forEach { it.join() }
}

withPermit 확장

semaphore.withPermit { ... }은 허가를 획득하고 블록을 실행한 뒤 허가를 반환합니다. 세마포어에서 허가를 획득하는 작업을 코루틴에 안전하게 적용한 방식입니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
fun main() = runBlocking {
    val sem = Semaphore(2)
    val results = mutableListOf<String>()
    List(5) { i ->
        launch {
            sem.withPermit {
                delay(50)
                synchronized(results) { results.add("task-$i") }
            }
        }
    }.forEach { it.join() }
    println(results)
}

세마포어로 속도 제한하기

세마포어를 사용하여 동시 API 호출 수를 제한하십시오. 한 번에 N개의 요청만 처리하도록 제한할 수 있습니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
val apiSemaphore = Semaphore(5) // max 5 concurrent requests
suspend fun callApi(id: Int): String {
    return apiSemaphore.withPermit {
        delay(100) // simulate network
        "Response-$id"
    }
}
fun main() = runBlocking {
    val results = (1..20).map { async { callApi(it) } }.awaitAll()
    println("Got ${results.size} responses")
}

Mutex와 Semaphore

Mutex: 허가가 1개인 이진 세마포어로, 배타적 접근에 사용합니다. Semaphore(n): 허가가 n개인 세마포어로, 동시 실행 수를 제한합니다. 리소스 보호에는 Mutex를 사용하고 병렬 처리량 제한에는 Semaphore를 사용하십시오.

import kotlinx.coroutines.sync.*
// Mutex = Semaphore(1) for exclusive access
// Semaphore(n) = n-way concurrency limit
val exclusive = Mutex()          // one at a time
val limited   = Semaphore(3)     // three at a time
fun main() { println("Mutex for exclusion; Semaphore for rate limiting") }

뮤텍스를 사용한 원자적 카운터

증가 및 읽기 작업을 보호하도록 Mutex를 사용하여 스레드 안전한 카운터 클래스를 구현하십시오.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
class AtomicCounter {
    private val mutex = Mutex()
    private var count = 0
    suspend fun increment() = mutex.withLock { count++ }
    suspend fun get() = mutex.withLock { count }
}
fun main() = runBlocking {
    val counter = AtomicCounter()
    List(100) { launch { counter.increment() } }.forEach { it.join() }
    println("Count: ${counter.get()}")
}

대안: 단일 스레드 디스패처

뮤텍스를 사용하는 대신 변경 가능한 상태를 단일 스레드 디스패처에 한정할 수 있습니다. 한 번에 하나의 코루틴만 해당 디스패처에서 실행되므로 접근이 본질적으로 안전해집니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val singleThread = newSingleThreadContext("CounterThread")
    var counter = 0
    List(1000) {
        launch(singleThread) { counter++ }
    }.forEach { it.join() }
    println("Counter: $counter") // 1000, no mutex needed
    singleThread.close()
}

빠른 확인

Mutex와 Semaphore의 핵심적인 차이점은 무엇입니까?

복습

Mutex는 공유 상태에 대한 배타적 접근을 제공하므로 withLock을 우선 사용하십시오. Semaphore(n)은 동시 실행 수를 n으로 제한합니다. 둘 다 대기 중인 코루틴을 차단하지 않고 일시 중단합니다. 간단한 경우에는 단일 스레드 디스패처가 더 깔끔한 경우가 많습니다.

자주 묻는 질문

“공유 상태를 위한 Mutex와 Semaphore” 강의는 무료인가요?

네 — “공유 상태를 위한 Mutex와 Semaphore” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Kotlin Academy 강의 전체를 잠금 해제할 수 있습니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“공유 상태를 위한 Mutex와 Semaphore”에서 뭘 배우나요?

Mutex로 공유 변경 가능 상태를 보호하고 Semaphore로 동시 실행을 제한해 보세요. 브라우저에서 직접 실행하는 실습 코드로 Kotlin Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Kotlin Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Kotlin Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“공유 상태를 위한 Mutex와 Semaphore” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Kotlin Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Kotlin Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 채널 기초: send, receive 및 close
  2. 채널 타입: 랑데부, 버퍼링, 융합, 무제한
  3. 공유 상태를 위한 Mutex와 Semaphore
  4. 액터와 구조화된 상태 관리
← Kotlin Academy(으)로 돌아가기