"내 변수 값이 왜 계속 바뀌죠?" 😭
멀티스레드 환경에서 개발하다 보면
"어? 값이 이상하게 바뀌네?"
"이 변수 왜 다른 스레드에도 공유되지?"
이런 황당한 상황을 한 번쯤 겪었을 겁니다.
이럴 때 딱 필요한 게 바로 ThreadLocal입니다!
오늘은 ThreadLocal이 무엇인지, 언제 어떻게 사용하는지
쉽고 빠르게 이해할 수 있도록 정리해드릴게요. 🚀
🧐 ThreadLocal이 뭐길래?
ThreadLocal은 각 스레드마다 독립적인 변수를 저장할 수 있는 기능입니다.
보통 공유 변수는 여러 스레드에서 동시에 접근해서 값이 꼬일 수 있는데,
ThreadLocal을 쓰면 각 스레드가 자기만의 값을 가짐! 🎯
💡 한 줄 요약:
"각 스레드가 자기 전용 변수를 가질 수 있게 해주는 기능!"
📌 ThreadLocal 기본 사용법 (초간단 예제)
public class ThreadLocalExample {
// ThreadLocal 인스턴스 생성
private static ThreadLocal<Integer> threadLocalValue = ThreadLocal.withInitial(() -> 0);
public static void main(String[] args) {
Runnable task = () -> {
threadLocalValue.set((int) (Math.random() * 100)); // 각 스레드마다 다른 값 저장
System.out.println(Thread.currentThread().getName() + " : " + threadLocalValue.get());
};
Thread t1 = new Thread(task, "Thread-1");
Thread t2 = new Thread(task, "Thread-2");
t1.start();
t2.start();
}
}
✅ ThreadLocal.withInitial(() -> 0); → 기본값 0으로 설정
✅ threadLocalValue.set(값); → 각 스레드에서 자기만의 값 저장
✅ threadLocalValue.get(); → 저장한 값 가져오기
🔥 실행하면?
각 스레드가 자기만의 값을 가지는 걸 확인할 수 있음!
🎯 ThreadLocal을 언제 써야 할까?
💡 ThreadLocal이 필요한 순간들!
1️⃣ 각 스레드가 독립적인 값을 가져야 할 때
- HTTP 요청 ID, 트랜잭션 ID 등 스레드별로 다른 값 관리
2️⃣ 멀티스레드 환경에서 안전한 데이터 저장
- 스프링에서 @Transactional이 Connection을 ThreadLocal에 저장하는 방식
3️⃣ 서블릿 필터에서 사용자 정보 저장
- 로그인한 사용자 정보를 ThreadLocal에 저장하고 컨트롤러에서 꺼내 쓰기
🔥 실전 예제: 로그인 사용자 정보 관리
👉 로그인한 유저 정보를 ThreadLocal로 저장해서 어디서든 꺼내 쓰기!
public class UserContext {
private static final ThreadLocal<String> userThreadLocal = new ThreadLocal<>();
public static void setUser(String username) {
userThreadLocal.set(username);
}
public static String getUser() {
return userThreadLocal.get();
}
public static void clear() {
userThreadLocal.remove(); // 메모리 누수 방지
}
}
// 서블릿 필터에서 로그인 정보 저장
public class AuthFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
String username = ((HttpServletRequest) request).getHeader("X-User");
UserContext.setUser(username); // ThreadLocal에 저장
chain.doFilter(request, response);
} finally {
UserContext.clear(); // 요청 처리 후 정리 (안 하면 메모리 누수 위험!)
}
}
}
// 컨트롤러에서 사용자 정보 활용
public class UserController {
public void handleRequest() {
System.out.println("현재 사용자: " + UserContext.getUser());
}
}
✅ 요청이 들어오면 AuthFilter에서 ThreadLocal에 사용자 정보 저장
✅ 컨트롤러에서 UserContext.getUser() 로 간편하게 가져다 씀
✅ 요청이 끝나면 clear() 로 메모리 누수 방지!
🚨 ThreadLocal 주의사항! (이거 안 지키면 큰일남!)
❌ 1. ThreadLocal은 꼭 remove() 해라!
→ clear() 안 하면 메모리 누수 발생 (특히 톰캣 같은 웹 서버에서 치명적)
❌ 2. 멀티스레드 환경에서 전역변수처럼 사용하면 안 됨
→ ThreadLocal은 스레드마다 다른 값을 저장하지만,
잘못 사용하면 데이터 꼬임 발생
❌ 3. ThreadPool을 사용할 때 조심하라!
→ 스레드가 재사용될 경우, 이전 값이 남아 있을 수 있음
(이럴 땐 remove() 필수!)
🎯 ThreadLocal 한 줄 정리!
✅ 각 스레드마다 독립적인 변수를 저장하는 기능
✅ 멀티스레드 환경에서 안전하게 데이터 관리 가능
✅ 로그인 정보, 트랜잭션 ID, 세션 정보 저장에 유용
✅ 사용 후 꼭 remove() 해서 메모리 누수 방지!
이제 ThreadLocal 개념 확실히 잡으셨죠? 😉
혹시 더 궁금한 점 있으면 댓글 남겨주세요! 💬✨
'Programming > JAVA' 카테고리의 다른 글
✅ Java Try-with-Resources, 제대로 알고 쓰자! (1) | 2025.03.02 |
---|---|
Java 리플렉션 API, 써보셨나요? 🤔 (0) | 2025.03.02 |