Thread Local 의 동작원리

2025. 2. 7. 17:59·Java

개요 

 

Java에서 ThreadLocal을 사용할 때 보통 아래와 같이 new 연산자를 통해 객체를 생성합니다.

private static final ThreadLocal<UUID> THREAD_LOCAL = new ThreadLocal<>();

 

처음에는 ThreadLocal 객체가 데이터를 저장하는 저장소 역할을 한다고 생각했지만, 코드를 분석해본 결과 ThreadLocal은 저장소가 아니라 각 스레드가 가지고 있는 저장소의 key 역할을 수행한다는 것을 알게 되었습니다.

 

ThreadLocal의 set() 메서드 분석

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        map.set(this, value);
    } else {
        createMap(t, value);
    }
}

 

현재 스레드 가져오기

  • Thread.currentThread()를 호출하여 현재 실행 중인 스레드를 가져옴

현재 스레드의 ThreadLocalMap 가져오기

ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}
  • Thread 객체의 threadLocals 필드를 반환하는데, 이 필드는 ThreadLocalMap 타입
/* 각 스레드가 가지고 있는 ThreadLocalMap */
ThreadLocal.ThreadLocalMap threadLocals = null;
  • 즉, ThreadLocal이 직접 값을 저장하는 것이 아니라, 각 Thread 객체가 자체적으로 관리하는 ThreadLocalMap에 데이터를 저장

 

ThreadLocalMap 내부 자료구조

static class ThreadLocalMap {

    static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;

        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
    ...

}
  • ThreadLocalMap 내부에는 Entry라는 내부 클래스를 가지고 있으며, 여기서 각 스레드에 할당된 ThreadLocal 데이터가 저장

 

set() 동작 과정

  • getMap(t)를 호출하여 ThreadLocalMap이 존재하는지 확인
  • 존재하면 map.set(this, value);를 호출하여 값을 저장
  • 존재하지 않으면 createMap(t, value);를 호출하여 새로운 ThreadLocalMap을 생성
 void createMap(Thread t, T firstValue) {
     t.threadLocals = new ThreadLocalMap(this, firstValue);
 }
  • Thread 객체의 threadLocals 필드에 ThreadLocalMap 객체를 생성하고, 현재 ThreadLocal 인스턴스와 초기값을 저장

 

ThreadLocalMap의 구조

ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
    table = new Entry[INITIAL_CAPACITY];
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    table[i] = new Entry(firstKey, firstValue);
    size = 1;
    setThreshold(INITIAL_CAPACITY);
}
  • table = new Entry[INITIAL_CAPACITY]; -> Entry[] 배열이 ThreadLocal의 키-값을 저장하는 공간
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
  • firstKey.threadLocalHashCode는 ThreadLocal 객체의 해시 코드
  • & (INITIAL_CAPACITY - 1) 비트 연산을 통해 해시 충돌을 최소화하여 해시인덱스를 생성
  •  i 는 해시 인덱스를 사용하여 O(1) 의 빠른성능을 보장
table[i] = new Entry(firstKey, firstValue);
  • firstKey는 현재 ThreadLocal 객체의 참조값이며, firstValue는 저장하려는 값
  • 해당 데이터를 Entry 객체로 생성하여 table에 저장
 

 

ThreadLocal의 get() 메서드 분석

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

 

현재 스레드에서 ThreadLocalMap 가져오기

  • getMap(Thread t)를 호출하여 현재 스레드의 ThreadLocalMap을 가져옴

 

현재 ThreadLocal의 값 찾기

  • map.getEntry(this); → 현재 ThreadLocal 객체의 참조값(this)을 키로 하여 Entry를 찾음
  • 만약 존재하면 값을 반환하고, 없으면 setInitialValue()를 호출하여 기본값을 설정

 

ThreadLocal의 remove() 메서드

  • 스프링 프레임워크에서는 스레드 풀 환경, 즉 스레드 풀은 스레드를 반복해서 재사용 이전 요청에서 설정된 ThreadLocal 값을 삭제해줘야 함
public void remove() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        map.remove(this);
    }
}​
  • remove()를 호출하면 현재 스레드의 ThreadLocalMap에서 해당 ThreadLocal 키를 삭제하여 불필요한 메모리 점유를 방지

 

 

결론 

각 스레드는 자체적으로 ThreadLocalMap을 가지고 있기 때문에 충돌 없이 스레드 세이프함
ThreadLocalMap의 내부 자료구조인 Entry는 ThreadLocal 자신의 객체를 키로 사용하여 데이터를 저장

하나의 스레드에서 여러 개의 ThreadLocal 객체를 사용할 수 있으며, 각각의 데이터를 안전하게 관리할 수 있음

 

 

ThreadLocal 인스턴스

ThreadLocal<T>
@x001
ThreadLocal<T>
@x002

 

Thread1.ThreadLocalMap

ThreadLocal<T> value
@x001 data
@x002 data2

 

 

Thread2.ThreadLocalMap

ThreadLocal<T> value
@x001 data
@x002 data2

 

즉, ThreadLocal은 데이터를 직접 저장하는 것이 아니라, 각 스레드마다 독립적인 저장소를 관리하는 key 역할을 수행하며, 이를 통해 멀티스레드 환경에서도 안전하게 데이터를 보관할 수 있습니다.

'Java' 카테고리의 다른 글

ExecutorService의 이해  (0) 2025.02.19
Spring Boot 엑셀 업로드 기능 개발기  (1) 2025.02.04
'Java' 카테고리의 다른 글
  • ExecutorService의 이해
  • Spring Boot 엑셀 업로드 기능 개발기
JoshDev
JoshDev
    • 분류 전체보기 (24)
      • Java (3)
      • Spring (9)
      • Test Code (2)
      • WIL (6)
      • Vue.js (2)
      • WEB (0)
      • DB (1)
        • MySQL (1)
  • 인기 글

  • hELLO· Designed By정상우.v4.10.4
JoshDev
Thread Local 의 동작원리
상단으로

티스토리툴바