개발이군고구마

Thread와 ThreadLocal 본문

SERVER/Spring

Thread와 ThreadLocal

김구황 2024. 10. 2. 12:23
728x90

1. 개요

- 애플리케이션에서 사용되는 객체는 스프링에서 “싱글톤” 으로 만들어져서 사용됨
- 스레드가 동시에 요청되는 경우에 heap영역에 있는 싱글톤 객체가 공유되어, 각기 다른 요청에 사용될 수 있음
- 스레드 동시성의 문제를 해결해야 각 스레드별 안전성을 확보할 수 있음  


2. Thread 란 무엇인가

- 실제로 작업을 수행하는 주체 
- 요청당 스레드가 할당 되며, 자바의 경우엔 멀티 스레드를 지원함 (ThreadPool) 

[thread와 요청을 쉽게 생각하는 방법]
- request : 주문
- thread : 점원
- WAS/브라우저 : 가게 

 
 
2-1. 자바 스크립트의 싱글 스레드와 비동기
- 자바 스크립트는 실행컨텍스트를 1개만 생성할 수 있는 싱글스레드 그러나,
- 브라우저가 멀티스레드를 지원하기 때문에 동시에 여러 요청이 와도 스레드를 처리할 수 있음
- 브라우저의 이벤트 루프가 비동기도 지원하고 있음
 
2-2. 자바의 멀티 스레드와 동기
- thread pool에서 thread를 할당하기 때문에 
- 동시에 여러 요청이 와도 처리 가능 
- 자바는 동기로 스레드 처리함 
 

 

 

3. 동시성 문제를 해결하는 ThreadLocal

JVM이 운영체제로부터 할당받은 메모리영역.

  • data 영역에서, thread가 heap 영역을 공유하고 있음
  • spring 싱글톤 패턴에서, 힙영역에 올라간 객체가 공유될 가능성이 있음

 

* 스레드 용 전용 보관소


- 각 Thread 별로 생성되는 변수

public class ThreadLocal<T> {

	...
    
    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();
    }
    
    ...
    
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            map.set(this, value);
        } else {
            createMap(t, value);
        }
    }
    
    ...
    
}

 

  • get : 현재 스레드의 고유한 로컬 변수 조회
  • set : 현재 스레드의 고유한 로컬 변수 값 저장
  • Map 형태로 저장 : key (현재 thread) : value (현재 threadlocal 변수 값)
    • => 해당 변수는 현재 thread에서만 사용이 가능함

 

4. 사용처

- 사용자 인증 정보, 트랜잭션 컨텍스트 등 스테드별로 “독립적으로” 유지해야하는 정보 저장시 활용
- 각 스레드가 사용자 별 세션 정보 유지나 현재 트랜잭션 상태를 스레드 별로 관리해야할 때
 
[예 - security authentication 객체 session 저장시]

public void setAuthentication(String userName){
	SecurityContext context = SecurityHolder.createEmptyContext();
    Authentication authentication = createAuthentication(userName);
    context.setAuthentication(authentication);
    
    SecurityHolder.setContext(context);
}
  • Thread가 동시에 요청이 오는 경우, 힙 영역에 저장된 객체는 공유가 됨
  • 그렇다면 SecurityHolder에 담기는 context는 중복될 가능성이 있는 거 아닐까? 

 
[SecurityContext의 threadLocal 사용]

  • SpringSecurityHolder에서 SecurityContext 클래스의 context를 조회하는 메서드를 호출
  • 그때 Context는 threadlocal에 저장된 thread별 securityContext 객체를 찾아서 넘김 
    • 따라서, 해당 thread 별 context (authentication)이 반환되어
    • 동시 thread 요청이 오더라도, 각각의 thread가 holder에 저장이 됨 

 


5. ThreadPool

- 다중요청을 처리하는 방법
- 서블릿 컨테이너 (Tomcat) 이 부팅시에 Thread Pool을 생성함
- 유저의 요청 (HttpServletRequest) 가 들어오면 Thread Pool에서 하나씩 Thread를 할당
 
 

 

[앞으로 궁금점]

Context와 Strategy 라고 써져 있는 클래스들이 많이 보이는데, 
이는 어떤 디자인 패턴을 따르고 있는 걸까 ?