Java에서 ThreadLocal이란 무엇인가요?

김상진 ·2025년 2월 25일
0

CS

목록 보기
32/34

"스레드마다 독립적인 저장공간을 가진다" – 이 한 줄이 핵심입니다.

✅ 1. ThreadLocal이란?

ThreadLocal<T>각 스레드마다 독립적인 값을 저장할 수 있게 해주는 Java 클래스입니다.
즉, 동일한 ThreadLocal 인스턴스를 여러 스레드가 공유하더라도 각 스레드는 자신만의 고유한 값을 갖습니다.

❗ 왜 필요한가요?

동시성 환경에서는 여러 스레드가 같은 변수에 접근할 경우 race condition이 발생합니다.
하지만 ThreadLocal을 사용하면 변수 자체를 스레드마다 격리시킬 수 있기 때문에 동기화 필요 없이 안전하게 사용할 수 있습니다.


🔧 2. 어떻게 동작하나요?

  • Thread 객체는 내부에 ThreadLocalMap이라는 저장소를 갖고 있음
  • ThreadLocal.set() → 현재 스레드의 ThreadLocalMap에 값 저장
  • ThreadLocal.get() → 현재 스레드 기준의 값 반환
  • 스레드가 다르면 ThreadLocal의 키는 같아도 값은 서로 다름
ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("Hello");

String value = threadLocal.get(); // 현재 스레드의 값만 반환

🧵 3. Spring 생태계에서의 ThreadLocal 사용 예시

Spring 내부에서도 ThreadLocal은 아래와 같은 기능 구현에 널리 활용되고 있습니다.

사용처설명
TransactionSynchronizationManager트랜잭션 컨텍스트 관리
SecurityContextHolder인증된 사용자 정보 보관
RequestContextHolderHTTP 요청 스코프 데이터 저장
Logging MDC (Mapped Diagnostic Context)로그 추적 시, 요청 ID 등 컨텍스트 정보 저장

✅ 4. 장점 요약

  • 스레드 간 데이터 격리 → 동기화 필요 없음
  • 코드가 깔끔해짐 (파라미터 전달 필요 없음)
  • Spring 내부처럼 컨텍스트 정보 전파에 유용

⚠️ 5. 실무에서 반드시 알아야 할 주의점

1. 스레드풀 재사용 시 ThreadLocal 유출

ThreadPool을 사용하는 경우, 스레드가 재사용되기 때문에 이전 작업의 ThreadLocal 값이 남아 있을 수 있습니다.

// 반드시 작업 끝나고 ThreadLocal 제거
threadLocal.remove();

정리하지 않으면 메모리 누수 또는 예기치 않은 값 공유 문제가 발생합니다.


2. 비동기 환경에서는 동작하지 않음

예를 들어 @Async 메서드에서는 다른 스레드가 사용되므로, 이전 스레드의 ThreadLocal 값을 참조할 수 없습니다.

해결책: Spring의 TaskDecorator 사용

@Bean
public TaskExecutor asyncExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setTaskDecorator(new ContextCopyingDecorator());
    return executor;
}

3. NamedThreadLocal로 디버깅 개선

Spring에서는 NamedThreadLocal을 제공하여 ThreadLocal 변수에 이름을 부여할 수 있습니다.

private static final ThreadLocal<String> userContext =
    new NamedThreadLocal<>("User Context");

디버깅이나 메모리 분석 시 "User Context"라는 이름이 보이기 때문에 추적이 훨씬 쉬워집니다.


🔄 6. ThreadLocal의 대체 수단은?

대체 수단장단점
메서드 인자 전달명시적이지만 번거로움
@RequestScope BeanHTTP 요청 단위 저장소, Spring에서 안전하게 관리됨
ConcurrentHashMap 등 동기화 자료구조ThreadLocal처럼 스레드 간 격리는 불가능

📚 참고 자료


✍️ 마무리

ThreadLocal은 매우 강력하지만, 동시에 신중하게 사용해야 하는 도구입니다.
트랜잭션, 인증 정보, 요청 컨텍스트 등 다양한 곳에 쓰일 수 있지만, 스레드풀과 비동기 환경에서는 반드시 수동 정리와 전파 전략이 필요합니다.

✔️ 쓰고 나면 꼭 remove()
✔️ 비동기 환경에서는 TaskDecorator
✔️ 디버깅은 NamedThreadLocal

profile
알고리즘은 백준 허브를 통해 github에 꾸준히 올리고 있습니다.🙂

0개의 댓글