스레드 로컬(Thread Local)이란?

2024. 12. 29. 11:48·💻 Dev/Java & OOP

스레드 로컬이란?

ThreadLocal은 멀티스레드 환경에서 각 스레드가 독립적인 데이터를 저장하고 관리할 수 있도록 지원하는 메커니즘이다.

https://wookkingkim.tistory.com/entry/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EB%8F%99%EA%B8%B0%ED%99%94Synchronization-%EA%B2%BD%EC%9F%81-%EC%83%81%ED%83%9CRace-Condition

 

여러 스레드가 동시에 실행되는 애플리케이션에서는 공유 데이터로 인해 경쟁 상태(race condition)가 발생할 수 있다.

이러한 문제를 방지하기 위해 데이터를 스레드 간에 독립적으로 관리해야 할 때 ThreadLocal을 사용할 수 있다.

 

 

스레드 로컬이 필요한 이유

1. 스레드 간 데이터 충돌 방지

멀티스레드 환경에서 동일한 데이터를 여러 스레드가 동시에 접근하면, 의도치 않은 결과가 발생할 수 있다.(ex. race condition) ThreadLocal은 각 스레드가 독립적인 데이터를 유지할 수 있도록 하여 이런 충돌을 방지한다.

 

2. 세션 및 사용자 정보 관리

웹 애플리케이션에서 각 클라이언트 요청은 별도의 스레드에서 처리된다. ThreadLocal을 사용하여 요청 ID, 사용자 정보 등을 저장하면 스레드 간 간섭 없이 데이터를 안전하게 관리할 수 있다.
그래서 ThreadLocal은 웹 애플리케이션에서 사용자 인증 정보를 관리하는 데 자주 사용된다.

 

3. 데이터베이스 트랜잭션 관리

트랜잭션 컨텍스트를 ThreadLocal에 저장하면, 동일한 스레드에서 실행되는 모든 데이터베이스 작업이 동일한 트랜잭션 범위에 속하도록 할 수 있다.

 

4. 로깅

로그를 기록할 때 요청별로 고유한 ID를 사용해야 할 경우, ThreadLocal을 사용하여 각 요청의 데이터를 관리할 수 있다.

 

 

Thread 내부 코드로 보는 스레드 로컬

public class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals;
    ThreadLocal.ThreadLocalMap inheritableThreadLocals;
}

Thread 클래스에는 threadLocals와 inheritableThreadLocals라는 두 개의 멤버 변수가 있다. 이 변수들은 스레드별로 데이터를 저장하는 데 사용된다.

- threadLocals: 각 스레드가 독립적으로 데이터를 저장하는 맵.
- inheritableThreadLocals: 부모 스레드의 데이터를 자식 스레드로 상속하기 위한 맵.

 

 

ThreadLocal 내부 구조

ThreadLocal클래스는 내부적으로 ThreadLocalMap을 사용하여 key/value로 데이터를 저장한다.

public class ThreadLocal<T> {
    static class ThreadLocalMap {
        static class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
    }
}

ThreadLocalMap은 ThreadLocal 객체를 키로 사용하여 데이터를 저장하고 값은 해당 객체에 할당된 데이터이다.

예를 들어 myThreadLocal.set(value)를 호출하면 threadLocals 맵에 {myThreadLocal: value} 형태로 저장된다.

 

ThreadLocal의 주요 메서드

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

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();
}

ThreadLocal의 get, set등의 메서드를 보면 Thread에서 현재 수행 중인 thread를 currentThread() 메서드를 통해 꺼낸 뒤 이 Thread에서 ThreadLocalMap을 찾아 리턴하는 것을 볼 수 있다.

 

 

inheritableThreadLocals

inheritableThreadLocals은 threadLocals과 유사하지만, 부모 스레드의 데이터를 자식 스레드로 상속할 수 있다는 차이가 있다.

 

요청을 처리하는 스레드가 오랜 특정 작업 때문에 기간 동안 점유되어 스레드 풀로 반환되지 않는다면 동시성이 떨어지게 된다. 이러한 문제를 해결하기 위해 요청의 작업들 중 일부는 비동기로 실행되도록 백그라운드 스레드로 위임시킬 수 있다. 그러면 백그라운드 스레드에서는 스레드 로컬에 저장된 값이 없게 되므로 문제가 생길 수 있으므로, 자바는 자식 스레드에게 스레드 로컬의 값을 위임시켜 주는 상속 가능한 InheritableThreadLocal을 제공하고 있다.

 

어떻게? 🤔

부모 스레드가 새로운 스레드를 생성할 때, inheritableThreadLocals 맵의 데이터를 복사하여 자식 스레드의 inheritableThreadLocals로 전달한다.
이를 통해 자식 스레드는 부모 스레드의 데이터를 초기값으로 가질 수 있다.

 

 

두 변수의 차이점

속성 threadLocals inheritableThreadLocals
관리 클래스 ThreadLocal InheritableThreadLocal
데이터 상속 상속되지 않음 부모 스레드의 데이터가 자식 스레드에 상속
사용 목적 각 스레드의 독립적 데이터 저장 부모-자식 스레드 간 데이터 공유
값 관리 주체 현재 스레드에만 접근 가능 자식 스레드에서 부모의 초기값 접근 가능

 

예제

다음은 ThreadLocal을 사용하여 각 스레드가 독립적인 값을 관리하는 예제이다.

public class ThreadLocalExample {  
    // ThreadLocal 변수 선언  
    private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);  

    public static void main(String[] args) {  
        Runnable task = () -> {  
            for (int i = 0; i < 5; i++) {  
                threadLocal.set(threadLocal.get() + 1); // 현재 스레드의 값 갱신  
                System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get());  
            }  
        };  

        // 두 개의 스레드 실행  
        Thread thread1 = new Thread(task);  
        Thread thread2 = new Thread(task);  

        thread1.start();  
        thread2.start();  
    }

결과를 보면 스레드별로 독립된 값을 유지하는 것을 볼 수 있다.

Thread-0: 1
Thread-0: 2
Thread-0: 3
Thread-0: 4
Thread-0: 5
Thread-1: 1
Thread-1: 2
Thread-1: 3
Thread-1: 4
Thread-1: 5

 

 

ThreadLocal 사용 시 주의점

ThreadLocal을 사용할 때 반드시 인지해야할 주의할 점이 있다. ThreadLocal을 사용할 때 반드시 초기화가 필요하다.

 

왜냐!

WAS(Tomcat)와 같은 환경에서는 스레드 풀을 사용하기 때문에, 스레드가 재사용되면서 이전 데이터가 남아 있는 문제가 발생할 수 있다. 따라서 사용이 끝난 후 반드시 ThreadLocal.remove()를 호출하여 데이터를 초기화해야 한다.
사용 후에 비워주지 않는다면 해당 Thread를 부여받게 되는 다른 사용자가 기존에 세팅된 ThreadLocal의 데이터를 공유하게 될 수도 있다.

 

 

 

 

 

참고
Java Thread Local(쓰레드 로컬)은 무엇일까?
스레드 로컬(ThreadLocal)과 상속 가능한 스레드 로컬( InheritableThreadLocal)에 대하여

저작자표시 비영리 (새창열림)

'💻 Dev > Java & OOP' 카테고리의 다른 글

로또 코드 예제로 이해해 보는 객체 지향 설계 5원칙(SOLID)  (0) 2025.02.18
싱글톤 패턴은 thread safe하지 않다?(개선 방식 4가지)  (0) 2025.02.11
JDBC 드라이버 로딩으로 알아보는 Class.forName  (0) 2025.01.03
자바 직렬화(Java Serializable)  (0) 2024.12.27
자바는 왜 Lambda&Stream을 도입했을까? feat.함수형 프로그래밍  (0) 2024.12.26
리플렉션(Reflection)으로 DI 구현해보기 +단점  (0) 2024.12.22
'💻 Dev/Java & OOP' 카테고리의 다른 글
  • 싱글톤 패턴은 thread safe하지 않다?(개선 방식 4가지)
  • JDBC 드라이버 로딩으로 알아보는 Class.forName
  • 자바 직렬화(Java Serializable)
  • 자바는 왜 Lambda&Stream을 도입했을까? feat.함수형 프로그래밍
현주먹
현주먹
대구 불주먹 출신 현주먹의 개발.log
  • 현주먹
    현주먹의 개발로그
    현주먹
  • 전체
    오늘
    어제
    • 전체글 (179)
      • 👶🏻 CS (15)
        • Operating System (7)
        • DB (5)
        • Data Structure (2)
        • Software Engineering (1)
      • 💻 Dev (54)
        • Java & OOP (24)
        • Spring (4)
        • DB&JPA (6)
        • Test Code (1)
        • JSP & Servlet (13)
        • Etc (6)
      • 💡 Algorithm (25)
        • 인프런 (9)
        • 백준 (16)
      • 🛠 DevOps & Tool (11)
        • Linux (4)
        • AWS (1)
        • Git (2)
        • Etc (4)
      • 📝 끄적끄적 (74)
        • 후기 및 회고 (11)
        • TDD, 클린 코드 with Java 17기 (3)
        • F-Lab (23)
        • 🖥️ 자바의 정석 (11)
        • 📖 Clean Code (3)
        • 항해99 코테 스터디 (11)
        • 📖 가상 면접 사례로 배우는 대규모 시스템 설계 .. (11)
  • 블로그 메뉴

    • 🐈‍⬛ GitHub
    • TIL repository
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 태그

    개발자취업
    jsp
    jsp 2.3 웹 프로그래밍: 기초부터 중급까지
    2025스프링캠프
    항해99
    자바의신절판
    JPA
    티스토리챌린지
    객체지향
    백준
    TDD 클린 코드 with Java
    f-lab 후기
    코딩테스트준비
    오라클
    C
    데브클럽
    개구리책
    코테스터디
    인프런 특정문자뒤집기
    NextSTEP
    F-Lab
    에프랩
    오블완
    에프랩 후기
    99클럽
    개발자멘토링
    til
    ==와 equals()
    자바의정석
    로또 미션
  • hELLO· Designed By정상우.v4.10.2
현주먹
스레드 로컬(Thread Local)이란?
상단으로

티스토리툴바