ThreadLocal이 뭐지?


ThreadLocal은 각 스레드별로 독립된 값을 저장할 수 있게 해주는 특별한 저장소 역할을 하는 객체이다.

fun main() {
    val threadLocal = ThreadLocal<String>()

    val thread1 = Thread {
        threadLocal.set("Thread 1 value")
        println("Thread 1: ${threadLocal.get()}")
    }

    val thread2 = Thread {
        threadLocal.set("Thread 2 value")
        println("Thread 2: ${threadLocal.get()}")
    }

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()
}

// 결과
Thread 2: Thread 2 value
Thread 1: Thread 1 value

여기서 알아두어야할 점

그러면 비슷하게 전역변수를 썼으면 어떻게 됐을까?

fun main() {
    val map = mutableMapOf<String, String>()

    val thread1 = Thread {
        map["value"] = "Thread 1 value"
        println("Thread 1: ${map["value"]}")
    }

    val thread2 = Thread {
        map["value"] = "Thread 2 value"
        println("Thread 2: ${map["value"]}")
    }

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()
}

// 결과
Thread 1: Thread 2 value
Thread 2: Thread 2 value

위 결과와 같이 여러 스레드가 일반 map 하나를 공유하게 되면 스레드 간 경합이 생기고, thread-safe 하지 않은 코드가 만들어진다. 예상 가능한 결과를 만들기 위해서는 동기화 기법을 사용해야하는 데, ThreadLocal은 이런 문제를 자연스럽게 피하는 것이다. (락 없이, 성능 저하 없이)

ThreadLocal 내부 메커니즘 살펴보기


threadLocal.set 메서드를 호출하면 다음과 같이 동작한다.

image.png

image.png

→ 즉, ThreadLocal 인스턴스 자체가 키 역할을 하면서, Thread 마다 따로 관리되는 Map 안에 값을 넣어두는 방식이다.