Backend/Java

ThreadLocal

findmypiece 2021. 3. 16. 01:56
728x90

Java에서 Thread의 로컬 컨텍스트 변수로 Thread 가 존재하는 한 계속해서 남아 있는 변수이다.

ThreadPool 에서 Thread를 관리하며 request당 하나의 Thread 를 사용하는 웹서버 특성상

하나의 request에서 공유되는 변수라고 생각하면 된다.

 

이걸 어디에 활용할 수 있나?

예를 들어 클래스끼리 전역으로 참조하고 싶은 데이터가 있다고 생각해보자.

java에서 가장 먼저 떠오르는 것은 static 변수이다.

하지만 static 변수는 모든 Thread 에서 공유되고

웹서버는 기본적으로 Multi Thread 방식이기 때문에 Thread Safe 하지 않다.

 

이때 Thread Local 을 사용할 경우 클래스끼리 전역적으로 참조할 수 있지만

다른 Thread에서는 참조할 수 없으므로 Thread Safe 한 데이터가 된다.

Thread Pool에 의해 Thread 가 재사용되는 웹서버의 특성상

해당 request 가 종료되는 시점에 Thread Local은 반드시 초기화 해줘야 한다.

 

일반적으로 아래와 같이 사용된다.

public class UserContext {

	private String id;
    private String name;
	
    public String getId(){
    	return this.id;
    }
	public String getName(){
    	return this.name;
    }
    public void setId(String id){
		this.id = id;
    }
	public String getName(String name){
	    this.name = name;
    }
}

public class UserContextHolder {
    private static final ThreadLocal<UserContext> userContextHolder = new ThreadLocal<>();

    private UserContextHolder() {
    }

    public static UserContext getUserContext() {
        return (UserContext)userContextHolder.get();
    }

    public static void setUserContext(UserContext userContext) {
        if (userContext == null) {
            userContextHolder.remove();
        }

        userContextHolder.set(userContext);
    }

    public static void resetUserContext() {
        userContextHolder.remove();
    }
}

public class Test {
  public void service(UserContext userContext){

    try{
	UserContextHolder.setUserContext(userContext);
	//타 메소드나 내부로직에서 UserContextHolder.getUserContext(); 활용..
    }finally{
    	UserContextHolder.resetUserContext();
    }
  }
}

 

만약 로깅에서 Thread 별로 공유하고 싶은 데이터가 있다면

slf4j,logback,log4j2 같은 로깅프레임워크에서 제공하는

MDC를 사용하는 것이 더 좋은 방법이다.

 

아래와 같이 간편하게 사용할 수 있고

MDC에 put 한 데이터가 있다면 log 출력시 함께 포함되서 출력된다.

MDC.put("id", "mypiece");
MDC.put("name", "piece");
log.info("mdc test");

MDC.clear();
log.info("mdc clear after");

 

 

궁금한 것은 Single Thread 방식인 nginx에서는 ThreadLocal을 활용할 수 있는가 이다.

event driven 방식이라면 이미 최초 요청과의 연결이 끊어진 상태 아닌가?

음 그래도 request가 온 곳으로 response 를 줘야 하니 연결은 되어 있어야겠네..

활용은 가능할거 같은데 안해봐서 모르겠다...

728x90

'Backend > Java' 카테고리의 다른 글

AutoBoxing과 AutoUnBoxing  (0) 2021.08.25
@Async, CompletableFuture, parallelStream  (0) 2021.07.14
Collections.EMPTY_LIST, Collections.EMPTY_MAP  (0) 2021.07.12
Map에 stream 사용하기  (0) 2021.06.18
jackson 역직렬화 시 주의할 점  (0) 2021.04.14