[kotlin] 코틀린에서의 스레드 간 통신 방법

코틀린은 자바와 마찬가지로 멀티 스레드 환경에서 작업을 수행할 수 있습니다. 하지만 스레드 간의 효율적인 통신은 중요한 과제 중 하나입니다. 이번 글에서는 코틀린에서 스레드 간 통신을 하는 몇 가지 방법을 알아보겠습니다.

1. 공유 변수 사용

가장 간단한 방법은 스레드 간에 공유 변수를 사용하는 것입니다. 공유 변수는 여러 스레드가 동시에 접근할 수 있는 변수를 의미합니다. 이를 위해 코틀린에서는 Atomic 타입 변수를 제공합니다.

다음은 AtomicInteger를 사용한 예시입니다.

import java.util.concurrent.atomic.AtomicInteger

fun main() {
    val sharedVariable = AtomicInteger(0)
    
    val thread1 = Thread {
        for (i in 1..1000) {
            sharedVariable.incrementAndGet()
        }
    }
    
    val thread2 = Thread {
        for (i in 1..1000) {
            sharedVariable.incrementAndGet()
        }
    }
    
    thread1.start()
    thread2.start()
    
    thread1.join()
    thread2.join()
    
    println("Result: ${sharedVariable.get()}")
}

이 예제는 AtomicInteger를 사용하여 두 개의 스레드가 공유 변수를 동시에 증가시키는 것을 보여줍니다. AtomicInteger는 원자적 연산을 지원하므로 정확한 결과를 보장합니다.

2. 락 사용

락은 스레드 간의 동기화 문제를 해결하는 데 도움이 됩니다. 크리티컬 섹션이라고 불리는 코드 영역을 한 번에 하나의 스레드만 실행하도록 보장합니다. 코틀린에서는 synchronized 키워드를 사용하여 락을 구현할 수 있습니다.

다음은 synchronized 키워드를 사용한 예시입니다.

fun main() {
    val sharedVariable = 0
    val lock = Object()
    
    val thread1 = Thread {
        synchronized(lock) {
            for (i in 1..1000) {
                sharedVariable++
            }
        }
    }
    
    val thread2 = Thread {
        synchronized(lock) {
            for (i in 1..1000) {
                sharedVariable++
            }
        }
    }
    
    thread1.start()
    thread2.start()
    
    thread1.join()
    thread2.join()
    
    println("Result: $sharedVariable")
}

이 예제는 synchronized 키워드를 사용하여 공유 변수에 접근하는 코드 영역을 동기화하고 있습니다. 이를 통해 락을 얻은 스레드만 해당 코드를 실행하고, 다른 스레드는 대기 상태로 들어갑니다.

3. 메시지 큐 사용

메시지 큐는 스레드 간 통신을 위한 더 복잡한 방법 중 하나입니다. 코틀린에서는 BlockingQueue 인터페이스를 사용하여 메시지 큐를 구현할 수 있습니다. 이를 통해 스레드 간에 메시지를 주고 받을 수 있습니다.

다음은 BlockingQueue를 사용한 예시입니다.

import java.util.concurrent.ArrayBlockingQueue

fun main() {
    val messageQueue = ArrayBlockingQueue<String>(10)
    
    val producer = Thread {
        for (i in 1..10) {
            val message = "Message $i"
            messageQueue.put(message)
            println("Produced: $message")
        }
    }
    
    val consumer = Thread {
        for (i in 1..10) {
            val message = messageQueue.take()
            println("Consumed: $message")
        }
    }
    
    producer.start()
    consumer.start()
    
    producer.join()
    consumer.join()
}

이 예제에서는 ArrayBlockingQueue를 사용하여 메시지 큐를 생성하고, 프로듀서 스레드와 컨슈머 스레드를 만들어 메시지를 주고 받고 있습니다.

마치며

이번 글에서는 코틀린에서의 스레드 간 통신 방법을 알아보았습니다. 공유 변수, 락, 메시지 큐를 활용하여 스레드 간에 데이터를 안전하게 전송할 수 있습니다. 선택한 방법은 프로젝트의 요구사항과 상황에 따라 다를 수 있으므로 적절히 선택해야 합니다.

📚 참고 자료