[개발 일기] 2025.04.14 - 스레드 로컬 (Thread Local)

2025. 4. 14. 13:15·개발 일기

💡 개요

 

오늘은 스레드 내부에서 저장소로 사용되는 기술인 스레드 로컬에 대해 정리해 보자.

 

 

 

🛠️ 스레드 로컬

 

스레드 로컬이란, 각 스레드가 고유하게 가지는 저장소를 의미한다.

 

 

멀티 스레드 환경에서 공유를 피하고 싶은 데이터가 있을 경우, 이를 ThreadLocal을 통해 각 스레드에 독립적으로 저장할 수 있다.

 

 

보통 스레드는 데이터를 힙 영역이나 스레드 로컬 영역에 저장할 수 있는데, 힙 영역에 저장된 데이터는 모든 스레드가 접근할 수 있어 공유되고, 스레드 로컬에 저장된 데이터는 해당 스레드에서만 접근 가능하므로 동시성 문제나 데이터 정합성 문제를 방지할 수 있다.

 

public class ThreadLocalTest {

    // 각 스레드마다 독립적인 값을 저장할 수 있는 ThreadLocal 변수
    private static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) {

        Runnable task = () -> {
            String threadName = Thread.currentThread().getName();
            threadLocal.set(threadName + "의 데이터");

            try {
                Thread.sleep(100); // 약간의 지연
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(threadName + " -> " + threadLocal.get());
        };

        Thread threadA = new Thread(task, "🧵Thread-A");
        Thread threadB = new Thread(task, "🧵Thread-B");

        threadA.start();
        threadB.start();
    }
}

 

[결과]
🧵Thread-B -> 🧵Thread-B의 데이터
🧵Thread-A -> 🧵Thread-A의 데이터

 

 

위 코드를 보면 ThreadLocal<String> threadLocal 은 모든 스레드가 공유하는 static 필드임에도 불구하고, 내부적으로는 각 스레드가 따로 값을 저장하므로, 스레드 A와 B는 서로의 데이터에 접근할 수 없다.

 

 

Spring MVC 구조에서는 일반적으로 요청이 Controller → Service → Repository 계층을 하나의 스레드에서 흐르게 된다.

 

 

이러한 구조 덕분에, 한 요청 안에서는 모든 계층에서 동일한 ThreadLocal 데이터를 조회할 수 있다.

 

 

이를 활용한 대표적인 예시가 데이터베이스에 접근할 때 사용되는 트랜잭션이다.

 

class MemberService {

    private final MemberRepository memberRepository;
    
    @Transactional
    public void signUp(...) {
        ...
        memberRepository.save(...);
    }
}

 

위 코드를 보면 데이터베이스에 회원 정보를 저장하는 메서드에 @Transactional이 설정되어 있다.

 

 

이것의 의미는 Service 계층에서 트랜잭션을 시작하고, Repository 계층에서 DB 커넥션을 사용해야 하는 것이다.

 

 

그런데 트랜잭션을 시작했는데 Repository에서는 이 트랜잭션이 뭔지 모르면 어떻게 될까..?

 

 

트랜잭션이 제대로 작동하지 않고, 데이터 정합성에 문제 생길 수 있다.

 

 

Spring은 이러한 문제를 해결하기 위해, 트랜잭션이나 DB 커넥션 객체를 스레드 로컬에 저장한다.

 

 

1. 트랜잭션 A 시작

  • → 현재 스레드에 해당 트랜잭션 관련 커넥션 객체를 ThreadLocal에 저장

 

2. 이후 Repository 계층에서 DB 접근

  • → ThreadLocal에서 현재 스레드의 커넥션을 꺼내 재사용

 

3. 트랜잭션 A 종료

  • → 커넥션 닫고, ThreadLocal.remove()로 정리

'개발 일기' 카테고리의 다른 글

[개발 일기] 2025.04.16 - 클래스가 final로 선언되면 내부 필드도 변경이 안될까?  (0) 2025.04.16
[개발 일기] 2025.04.15 - 자바 vector  (1) 2025.04.15
[개발 일기] 2025.04.13 - CQRS  (0) 2025.04.13
[개발 일기] 2025.04.12 - 프로세스 vs 스레드  (0) 2025.04.12
[개발 일기] 2025.04.11 - String vs StringBuffer vs StringBuilder  (1) 2025.04.11
'개발 일기' 카테고리의 다른 글
  • [개발 일기] 2025.04.16 - 클래스가 final로 선언되면 내부 필드도 변경이 안될까?
  • [개발 일기] 2025.04.15 - 자바 vector
  • [개발 일기] 2025.04.13 - CQRS
  • [개발 일기] 2025.04.12 - 프로세스 vs 스레드
오도형석
오도형석
  • 오도형석
    형석이의 성장일기
    오도형석
  • 전체
    오늘
    어제
    • 분류 전체보기 N
      • MSA 모니터링 서비스
        • DB
      • 스파르타 코딩클럽
        • SQL
        • Spring
      • 백엔드
        • Internet
        • Java
        • DB
      • 캡스톤
        • Django
        • 자연어처리
      • Spring
        • JPA
        • MSA
      • ETC
        • ERROR
      • 개발 일기 N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 인기 글

  • 태그

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
오도형석
[개발 일기] 2025.04.14 - 스레드 로컬 (Thread Local)
상단으로

티스토리툴바