본문 바로가기
Kotlin/비동기 프로그래밍

[Kotlin] 코루틴 동기화 방법

by startSW 2023. 11. 22.

코루틴은 동시성 작업을 다루는 데 유용한 도구이며, 동시에 여러 코루틴이 접근하는 공유 데이터에 대한 동기화를 효과적으로 처리할 수 있습니다.

 

1. Mutex (Mutual Exclusion)

코루틴 간에 공유된 데이터에 안전하게 접근하기 위해 Mutex를 사용할 수 있습니다.

Mutex는 임계 영역(Critical Section)을 설정하여 한 번에 하나의 코루틴만 해당 영역에 접근할 수 있게 합니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

var sharedVariable = 0
val mutex = Mutex()

suspend fun increment() {
    mutex.withLock {
        // 여기서의 코드는 오직 한 코루틴만 실행됩니다.
        sharedVariable++
    }
}

fun main() = runBlocking {
    val job = launch {
        repeat(1000) {
            increment()
        }
    }

    val job2 = launch {
        repeat(1000) {
            increment()
        }
    }

    job.join()
    job2.join()

    println("Result: $sharedVariable") // Result: 2000
}

 

2. CoroutineContext를 공유

CoroutineContext를 공유하여 코루틴 간에 공유 데이터에 안전하게 접근할 수 있습니다.

이 방법은 코루틴이 실행되는 환경을 공유함으로써 동기화를 달성합니다.

import kotlinx.coroutines.*

val sharedContext = newSingleThreadContext("sharedContext")

suspend fun safeUpdateSharedData() = withContext(sharedContext) {
    // 공유 데이터 업데이트
}

 

3. Actor 패턴

Actor는 코루틴 간에 메시지를 보내고 받는 메커니즘을 제공합니다.

Actor를 사용하면 메시지 처리가 순차적으로 이루어지므로 공유 상태에 대한 동기화를 신경 쓸 필요가 없습니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.actor

sealed class Message
data class UpdateData(val data: Int) : Message()

val actor = GlobalScope.actor<Message> {
    var sharedData = 0
    for (msg in channel) {
        when (msg) {
            is UpdateData -> sharedData += msg.data
        }
    }
}

// 사용
runBlocking {
    actor.send(UpdateData(42))
}

 

4. Atomic 변수 사용

Atomic 타입은 원자성을 보장하여 여러 스레드나 코루틴에서 안전하게 값을 읽고 쓸 수 있도록 도와줍니다.

import kotlinx.coroutines.*
import java.util.concurrent.atomic.AtomicInteger

val atomicVariable = AtomicInteger(0)

suspend fun increment() {
    atomicVariable.incrementAndGet()
}

fun main() = runBlocking {
    val job = launch {
        repeat(1000) {
            increment()
        }
    }

    val job2 = launch {
        repeat(1000) {
            increment()
        }
    }

    job.join()
    job2.join()

    println("Result: ${atomicVariable.get()}") // Result: 2000
}

 

 

'Kotlin > 비동기 프로그래밍' 카테고리의 다른 글

[Kotlin] 스레드간 동기화 방법  (0) 2023.11.22