java.lang.ThreadLocal

soomin·2021년 8월 18일
0

Java-API

목록 보기
1/1

출처 : 자바 캔(최범균 선생님) https://javacan.tistory.com/entry/ThreadLocalUsage

0. ThreadLocal


일반 변수의 수명은 코드블록 내부에서만 유효하다.

{
int a = 10;

///블록 내부에서 a 사용가능
}
// 자신을 둘러싸고있는 코드블록을 벗어나면, a 의 생명주기는 끝난다.

ThreadLocal 은 쓰레드 영역에 변수를 설정하는 방법이다. 특정 쓰레드가 실행되는 모든 코드에서 그 쓰레드에 설정된 변수 값을 사용할 수 있게 된다.



쓰레드 로컬 변수의 동작 방법은 다음과 같다.

💫 주목할 점은 Thread1 에서 실행할 경우 값이 Thread1 에 저장되고, Thread2 에서 실행할 경우 값이 Thread2 에 저장된다는 점이다.



1. ThreadLocal 클래스 사용법


  1. ThreadLocal 객체를 생성
  2. ThreadLocal#set() 메소드로 현재 동작하는 쓰레드 영역의 로컬변수에 값을 저장한다.
  3. ThreadLocal#get() 메소드로 현재 동작하는 쓰레드 영역의 로컬변수 값을 읽어들인다.
  4. ThreadLocal#remove() 메소드로 현재 동작하는 쓰레드 영역의 로컬변수 값을 삭제한다.
public class StaticThreadLocal {
    public static ThreadLocal<Domain>threadLocalVariable= new ThreadLocal();
}



2. ThreadLocal 클래스를 가지는 코드


하나의 Thread 에서 공통적으로 사용할 수 있는 Thread 영역의 로컬변수이므로, a()→b()→c() 로 이어지는 하나의 Thread 상에서 threadLocal 에 저장된 값은 모두 동일하다.

코드의 핵심은 메소드 인자로 Domain 객체를 넘겨주지않아도 같은 Thread 에서 동작하는 코드 간에는 같은 객체를 참조할 수 있다는 것이다.

class A {
    public void a() {
    	String name = Thread.currentThread().getName();
        
        System.out.printf("Thread : %s , ThreadLocal 내부에 값 여부: %s%n",
        		name, StaticThreadLocal.threadLocalVariable.get());
                
        Domain soomin = new Domain("soomin", 29, name);
        StaticThreadLocal.threadLocalVariable.set(soomin);

        B b = new B();
        b.b();
        
        System.out.printf("\n도메인 객체에 저장된 Thread 이름 : %s %n",
        		StaticThreadLocal.threadLocalVariable.get().getCurrentThread());
                
        StaticThreadLocal.threadLocalVariable.remove();
    }
}

class B {
    public void b() {
        Domain b = StaticThreadLocal.threadLocalVariable.get();
        System.out.printf("b() 함수에서 꺼내온 ThreadLocal 값 : %s%n",domain);

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

class C {
    public void c() {
        Domain domain = StaticThreadLocal.threadLocalVariable.get();
        System.out.printf("c() 함수에서 꺼내온 ThreadLocal 값 : %s%n",domain);
    }
}



3. ThreadLocal 은 파라미터를 사용하지 않고 값을 전달할 수 있게 해준다.


  • Spring Security 의 AuthenticationToken 은 ThreadLocal 에 저장되어있고, 어디서나 호출된다.
  • TransactionManager 의 트랜잭션 컨텍스트 전파
  • 쓰레드에 안전해야하는 데이터 보관

Thread 기준으로 동작하는 코드에 대해서는 ThreadLocal 을 사용하는 것이 유용하다.

public static void main(String[] args) throws InterruptedException {
    Thread other = new Thread(() -> new A().a(),"other");
	System.out.println("============other 실행=============");
    other.start();

    Thread.sleep(500);
    System.out.println("\n============main 실행=============");
    new A().a();

    System.out.println("\n============main 에서 다시 실행=============");
    new A().a();

}
/*
============other 실행=============
Thread : other , ThreadLocal 내부에 값 여부: null
b() 함수에서 꺼내온 ThreadLocal 값 : Domain{name='soomin', age=29, currentThread='other'}
c() 함수에서 꺼내온 ThreadLocal 값 : Domain{name='soomin', age=29, currentThread='other'}

도메인 객체에 저장된 Thread 이름 : other 

============main 실행=============
Thread : main , ThreadLocal 내부에 값 여부: null
b() 함수에서 꺼내온 ThreadLocal 값 : Domain{name='soomin', age=29, currentThread='main'}
c() 함수에서 꺼내온 ThreadLocal 값 : Domain{name='soomin', age=29, currentThread='main'}

도메인 객체에 저장된 Thread 이름 : main 

============main 에서 다시 실행=============
Thread : main , ThreadLocal 내부에 값 여부: null
b() 함수에서 꺼내온 ThreadLocal 값 : Domain{name='soomin', age=29, currentThread='main'}
c() 함수에서 꺼내온 ThreadLocal 값 : Domain{name='soomin', age=29, currentThread='main'}

도메인 객체에 저장된 Thread 이름 : main 
*/



4. Thread Pool


  • Thread Pool 은 Thread 를 "재사용"하기 때문에, ThreadLocal 에서 사용한 데이터 사용이 끝나면 반드시 ThreadLocal#remove() 를 호출하여 데이터를 삭제해야한다.
  • Thread Per Request Model로 작동하는 Apache Tomcat 같은 애들..
profile
블로그 유목민

0개의 댓글