ThreadLocal은 한 쓰레드에서 읽고 쓰여질 수 있는 변수를 할당하여 접근할 수 있도록 합니다. 멀티 쓰레드 환경에서 각 쓰레드마다 get(), set() 메서드를 통해 독립적으로 변수에 접근 할 수 있습니다. 말그대로 Thread 내부에서 사용하는 지역변수입니다.
public class ThreadLocalExam{
public static ThreadLocal<String> myThreadLocal = new ThreadLocal<>(); // ThreadLocal 객체를 생성
public static void main(String[] args){
myThreadLocal.set("Hello World!"); // ThreadLocal 객체에 변수를 할당한다.
String myThreadLocalValue = myThreadLocal.get(); // ThreadLocal 객체에 변수를 읽어온다.
System.out.println(myThreadLocalValue);
myThreadLocal.remove(); // ThreadLocal 객체의 remove() 메서드를 통해서 현재 ThreadLocal에 할당되어 있는 변수들을 삭제한다.
}
}
각 Thread마다 다른 랜덤 값이 할당되는 ThreadLocal 예제
import java.util.Random;
public class Context{
public static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> new Random().nextInt(100));
}
위 코드는 ThreadLocal 을 담고 있는 컨테이너 클래스입니다. 내부에 있는 ThreadLocal 객체는 초기화 시 랜덤한 정수 값을 할당하도록 구현되어 있습니다.
public class Foo{
private String threadName;
public Foo(String threadName){
this.threadName = threadName;
}
public void foo(){
System.out.println("Foo called by " + threadName + "=" + Context.threadLocal.get());
Bar bar = new Bar(threadName);
bar.bar();
}
}
public class Bar{
private String threadName;
public Bar(String threadName){
this.threadName = threadName;
}
public void bar(){
System.out.println("Bar called by " + threadName + " = " + Context.threadLocal.get());
}
}
public class ThreadLocalExam_2{
public static void main(String[] args){
Thread first = new Thread(() -> {
System.out.println("first thread = " + Context.threadLocal.get());
Foo foo = new Foo("First thread = ");
foo.foo();
});
Thread second = new Thread(() -> {
System.out.println("second thread = " + Context.threadLocal.get());
Foo foo = new Foo("second thread = ");
foo.foo();
});
first.start();
second.start();
}
}
결과
위 코드를 실행시킨 결과로 같은 Thread에서는 ThreadLocal 변수에 할당되어 있는 값들이 공유되고 다른 쓰레드와는 값이 다른 것을 확인할 수 있습니다. 즉, ThreadLocal의 변수는 각 쓰레드마다 독립되어 존재함을 알 수 있습니다.
ThreadLocal은 한 쓰레드에서 실행되는 코드가 동일한 객체를 사용할 수 있도록 해주기 때문에 쓰레드와 관련된 코드에서 파라미터를 사용하지 않고 객체를 전파하기 위한 용도로 주로 사용됩니다.
만약 ThreadPool과 같은 환경에서 ThreadLocal을 사용한다면 ThreadLocal 변수에 보관되어 있는 데이터의 사용이 끝나면 반드시 remove() 메서드를 통해 삭제해주어야 합니다.
ThreadPool을 통해 쓰레드를 재사용하는 경우에 이전에 사용했던 값을 공유할 수 있기 때문입니다.