저작권 안내: 저작권자표시 Yes 상업적이용 No 컨텐츠변경 No

스프링5 입문

JSP 2.3

JPA 입문

DDD Start

인프런 객체 지향 입문 강의
자바 1.2 버전부터 제공되고 있지만 아직 다수의 개발자들이 잘 몰라서 활용을 잘 못하는 기능이 하나 있는데, 그 기능이 바로 쓰레드 단위로 로컬 변수를 할당하는 기능이다. 이 기능은 ThreadLocal 클래스를 통해서 제공되는데, 본 글에서는 ThreadLocal 클래스의 기본적인 사용방법과 활용 방법을 살펴보도록 하겠다.

ThreadLocal이란?

일반 변수의 수명은 특정 코드 블록(예, 메서드 범위, for 블록 범위 등) 범위 내에서만 유효하다.

{
    int a = 10;
    ...
   // 블록 내에서 a 변수 사용 가능
}
// 변수 a는 위 코드 블록이 끝나면 더 이상 유효하지 않다. (즉, 수명을 다한다.)

반면에 ThreadLocal을 이용하면 쓰레드 영역에 변수를 설정할 수 있기 때문에, 특정 쓰레드가 실행하는 모든 코드에서 그 쓰레드에 설정된 변수 값을 사용할 수 있게 된다. 아래 그림은 쓰레드 로컬 변수가 어떻게 동작하는 지를 간단하게 보여주고 있다.


위 그림에서 주목할 점은 동일한 코드를 실행하는 데, 쓰레드1에서 실행할 경우 관련 값이 쓰레드1에 저장되고 쓰레드2에서 실행할 경우 쓰레드2에 저장된다는 점이다.


ThreadLocal의 기본 사용법

ThreadLocal의 사용방법은 너무 쉽다. 단지 다음의 네 가지만 해 주면 된다.
  1. ThreadLocal 객체를 생성한다.
  2. ThreadLocal.set() 메서드를 이용해서 현재 쓰레드의 로컬 변수에 값을 저장한다.
  3. ThreadLocal.get() 메서드를 이용해서 현재 쓰레드의 로컬 변수 값을 읽어온다.
  4. ThreadLocal.remove() 메서드를 이용해서 현재 쓰레드의 로컬 변수 값을 삭제한다.
아래 코드는 ThreadLocal의 기본적인 사용방법을 보여주고 있다.

// 현재 쓰레드와 관련된 로컬 변수를 하나 생성한다.
ThreadLocal<UserInfo> local = new ThreadLocal<UserInfo>();

// 로컬 변수에 값 할당
local.set(currentUser);

// 이후 실행되는 코드는 쓰레드 로컬 변수 값을 사용
UserInfo userInfo = local.get();

위 코드만으로는 ThreadLocal이 어떻게 동작하는 지 잘 이해가 되지 않을테니, 구체적인 예제를 이용해서 ThreadLocal의 동작 방식을 살펴보도록 하겠다. 먼저 ThreadLocal 타입의 static 필드를 갖는 클래스를 하나 작성해보자.

public class Context {
    public static ThreadLocal<Date> local = new ThreadLocal<Date>();
}

이제 Context 클래스를 사용해서 쓰레드 로컬 변수를 설정하고 사용하는 코드를 작성할 차례이다. 아래는 코드의 예이다.

class A {
    public void a() {
        Context.local.set(new Date());
       
        B b = new B();
        b.b();

        Context.local.remove();
    }
}

class B {
    public void b() {
        Date date = Context.local.get();

        C c = new C();
        c.c();
    }
}

class C {
    public void c() {
        Date date = Context.local.get();
    }
}

위 코드를 보면 A, B, C 세 개의 클래스가 존재하는데, A.a() 메서드를 호출하면 다음 그림과 같은 순서로 메서드가 실행된다.


위 그림에서 1~10은 모두 하나의 쓰레드에서 실행된다. ThreadLocal과 관련된 부분을 정리하면 다음과 같다.
  • 2 - A.a() 메서드에서 현재 쓰레드의 로컬 변수에 Date 객체를 저장한다.
  • 4 - B.b() 메서드에서 현재 쓰레드의 로컬 변수에 저장된 Date 객체를 읽어와 사용한다.
  • 6 - C.c() 메서드에서 현재 쓰레드의 로컬 변수에 저장된 Date 객체를 읽어와 사용한다.
  • 9 - A.a() 메서드에서 현재 쓰레드의 로컬 변수를 삭제한다.
위 코드에서 중요한 건 A.a()에서 생성한 Date 객체를 B.b() 메서드나 C.c() 메서드에 파라미터로 전달하지 않는다는 것이다. 즉, 파라미터로 객체를 전달하지 않아도 한 쓰레드로 실행되는 코드가 동일한 객체를 참조할 수 있게 된다.

ThreadLocal의 활용

ThreadLocal은 한 쓰레드에서 실행되는 코드가 동일한 객체를 사용할 수 있도록 해 주기 때문에 쓰레드와 관련된 코드에서 파라미터를 사용하지 않고 객체를 전파하기 위한 용도로 주로 사용되며, 주요 용도는 다음과 같다.

  • 사용자 인증정보 전파 - Spring Security에서는 ThreadLocal을 이용해서 사용자 인증 정보를 전파한다.
  • 트랜잭션 컨텍스트 전파 - 트랜잭션 매니저는 트랜잭션 컨텍스트를 전파하는 데 ThreadLocal을 사용한다.
  • 쓰레드에 안전해야 하는 데이터 보관

이 외에도 쓰레드 기준으로 동작해야 하는 기능을 구현할 때 ThreadLocal을 유용하게 사용할 수 있다.

ThreadLocal 사용시 주의 사항

쓰레드 풀 환경에서 ThreadLocal을 사용하는 경우 ThreadLocal 변수에 보관된 데이터의 사용이 끝나면 반드시 해당 데이터를 삭제해 주어야 한다. 그렇지 않을 경우 재사용되는 쓰레드가 올바르지 않은 데이터를 참조할 수 있다.


Posted by 최범균 madvirus

댓글을 달아 주세요

  1. 협객 2009.05.24 22:37 신고  댓글주소  수정/삭제  댓글쓰기

    안녕하세요 ^^
    너무 좋은 글이라 제 카페에 펌질을 하였습니다. ^^;
    출처는 밝혔습니다만 혹시 문제되시면 말씀해주세요.
    감사합니다.

  2. 제주소년 2009.09.01 14:05 신고  댓글주소  수정/삭제  댓글쓰기

    좋은글 감사합니다 ^^

  3. Hugh 2010.02.04 18:41 신고  댓글주소  수정/삭제  댓글쓰기

    좋은 글 감사합니다. 이게 정확하게 어떻게 쓰는지 몰라서 고민하고 있던 찰라에 명확한 해법이네요.

  4. JG 2010.10.08 16:02 신고  댓글주소  수정/삭제  댓글쓰기

    깔끔한 해석과 정리. 감사합니다. 많은 도움이 되었습니다.

  5. nnoonn 2011.07.14 10:37 신고  댓글주소  수정/삭제  댓글쓰기

    글이 너무 좋아서 제 블로그에 퍼갈게요~~
    제 블로그 주소 : http://blog.naver.com/iukim21c
    혹 안된다면 멜이나 댓글남겨주시면 바로 처리 할게요~~

  6. 파랑보석 2011.11.08 11:33 신고  댓글주소  수정/삭제  댓글쓰기

    좋은 정보 주셔서 감사합니다.
    출처와 이름 밝히고 펌해 갑니다.^^

  7. 서향 2012.05.03 10:08 신고  댓글주소  수정/삭제  댓글쓰기

    좋은정보 잘 보고 갑니다.

  8. 주한길 2013.01.28 13:03 신고  댓글주소  수정/삭제  댓글쓰기

    좋은글 출처를 표시하고 블로그에 담아갑니다. ^^

  9. me 2013.02.08 15:10 신고  댓글주소  수정/삭제  댓글쓰기

    이해가 잘되는 글이네요! 블로그에 퍼갑니다. 출처와 이름 남길게요~ 감사합니다

  10. bluepoet 2013.05.16 11:43 신고  댓글주소  수정/삭제  댓글쓰기

    저희도 ThreadLocal을 쓰고 있는데 왜 쓰는지도 모르고 쓰고 있었네요.

    좋은 글 감사합니다^^

  11. 방글라 2013.09.23 14:07 신고  댓글주소  수정/삭제  댓글쓰기

    담아갑니다.^^

  12. nklee 2014.04.11 15:36 신고  댓글주소  수정/삭제  댓글쓰기

    한 가지 질문이 있어서 이렇게 글 남깁니다.
    "쓰레드 풀 환경에서 ThreadLocal을 사용하는 경우 ThreadLocal 변수에 보관된 데이터의 사용이 끝나면 반드시 해당 데이터를 삭제해 주어야 한다" <== 현재 tomcat을 기반으로 웹 애플리케이션을 기도하게 되면 tomcat에서 제공해주고 있는 쓰레드 풀을 사용하게 되는데요.

    혹, 이런 경우 remove를 명시적으로 하지 않았을 때 문제가 발생되는 건가요?

    • 최범균 madvirus 2014.04.14 12:37 신고  댓글주소  수정/삭제

      예를 들어, ThreadLocal에 현재 로그인 한 사용자 정보 user1 객체를 보관했다고 해 보죠. 만약 remove를 하지 않는다면, 이후 같은 쓰레드를 사용해서 처리하는 웹브라우저의 요청은 마치 user1이 요청한 것처럼 처리될 수 있습니다.

  13. 천기자 2018.03.07 13:38 신고  댓글주소  수정/삭제  댓글쓰기

    위 예제를 실제로 코딩하려면 어떻게 해야하나요?
    main() 안에 그대로 적으면 되요?

  14. tester 2018.04.17 16:51 신고  댓글주소  수정/삭제  댓글쓰기

    와우.. 정말 잘 정리되었네요

    감사합니다 : )