ThreadLocal 사용 시 `remove()` 호출이 필수적인 이유
카테고리
프로그래밍/소프트웨어 개발
서브카테고리
DevOps
대상자
Java 개발자, 특히 스레드 풀을 사용하는 백엔드/시스템 엔지니어 (중간 난이도)
핵심 요약
- 스레드 풀에서
ThreadLocal
사용 시remove()
호출을 생략하면 메모리 누수 및 데이터 유출 발생 ThreadLocalMap
은 스레드 수명 동안 유지되며, GC에 의존하는 방식은 불확실try-finally
블록 또는withThreadLocal
헬퍼 메서드 사용이 권장threadLocal.remove()
강제 호출ThreadLocalMap
의 내부 참조를 명시적으로 해제
섹션별 세부 요약
1. 스레드 풀에서 `ThreadLocal` 사용 시 발생하는 문제
- 스레드 재사용으로 인한 데이터 유출
task1
에서 설정한ThreadLocal
값이task2
에서 접근 가능- 예상 출력:
Task 2: null
→ 실제 출력:Task 2: User A
- 메모리 누수 원인
- 스레드 풀의 스레드는 종료되지 않아
ThreadLocalMap
도 지속됨 ThreadLocal
변수 자체가 GC되더라도 내부ThreadLocalMap
참조로 값이 보존될 수 있음
2. `remove()` 호출을 통한 해결 방법
try-finally
블록 사용
```java
Runnable safeTask = () -> {
try {
threadLocal.set("User B");
System.out.println("Safe Task: " + threadLocal.get());
} finally {
threadLocal.remove(); // 강제 해제 필수
}
};
```
- 헬퍼 메서드 추상화
```java
public static void withThreadLocal(String value, Runnable action) {
threadLocal.set(value);
try {
action.run();
} finally {
threadLocal.remove();
}
}
```
executor.execute(() -> withThreadLocal("User C", () -> {...}))
형태로 사용
3. `ThreadLocalMap`의 내부 동작 원리
- 스레드 내부
ThreadLocalMap
구조 Thread
객체는ThreadLocalMap
참조를 유지- 스레드가 재사용될 경우,
ThreadLocalMap
은 기존 값 유지 - GC의 한계
ThreadLocal
변수가 GC되더라도ThreadLocalMap
의 내부 참조로 인해 데이터가 남아 있을 수 있음- "자동 정리"에 의존하는 것은 위험
결론
- 스레드 풀에서
ThreadLocal
사용 시remove()
을 반드시 호출 try-finally
블록 또는 헬퍼 메서드 사용 권장ThreadLocalMap
의 내부 참조 관리가 메모리 누수 예방 핵심- "자동 정리" 대신 명시적 정리가 필수적