Ver : Java SE 11
Module : java.base
Package : java.lang
public class ThreadLocal<T> extends Object
ThreadLocal 클래스는 스레드 독립적으로 사용 할 지역변수이다.
같은 스레드라면 어느 곳에서나 get, set method 를 통해 같은 변수를 불러오거나 설정할 수 있고,
스레드 독립적이므로 각 스레드가 갖고 있는 지역변수는 독립적이다.
ThreadLocal's Mehod
| Modifier And Type | Method | Description |
| T | get() | 이 thread-local 변수의 현재 thread의 사본에 있는 값을 반환 |
| protected T | initialValue() | 이 thread-local 변수에 대한 현재 thread의 초기 값을 반환 |
| void | remove() | 이 thread-local 변수에 대한 현재 thread 값을 제거 |
| void | set(T value) | 이 thread-local 변수의 현재 thread의 사본을 지정된 값으로 설정 |
| static <S> ThreadLocal<S> | withInitial(Supplier<? extends S> supplier) | thread 지역 변수를 생성 |
위 메서드를 보면 이해했을 수도 있겠지만, ThreadLocal 을 이해하려면 Thread class 의 인스턴스 변수 threadLocals 를 알아야 한다.
Thread 클래스에는 threadLocals 라는 인스턴스 변수가 선언되어있고, ThreadLocal 클래스는 get() or set() method 를 통해 threadLocals 에 값을 저장하거나 읽어오는 방식으로 동작한다.
public class Thread implements Runnable {
...
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
...
}
public class ThreadLocal<T> {
...
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t); // Thread t 의 threadLocals 변수를 반환한다.
if (map != null) {
map.set(this, value); // threadLocals 를 value 로 저장한다.
} else {
createMap(t, value); // threadLocals 이 null 일 경우 value 값을 갖고 있는 ThreadLocalMap 객체를 생성하여 저장한다.
}
}
...
}
threadLocals 변수는 package private 이며 ThreadLocal 클래스의 인스턴스가 생성될 때 마다 hash map 형태로 저장하기 때문에 static method 를 갖는 별도의 클래스를 생성하여 사용하여야 한다.
예시
class ThreadScore {
private static final ThreadLocal<Integer> threadScore = new ThreadLocal<>();
public static Integer get() {
return threadScore.get();
}
public static void set(Integer score) {
threadScore.set(score);
}
}
ThreadLocal 클래스를 통해 직접 접근해 보았지만 같은 Thread 라고 하더라도 hashmap 형태로 저장하고 있기 때문에 동일한 변수를 가져올 수 없다.
public void threadLocalDirect() {
ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
threadLocal.set(89);
System.out.println(Thread.currentThread().getName() + " - threadLocalDirect > get:" + threadLocal.get());
ThreadScore.set(91);
System.out.println(Thread.currentThread().getName() + " - threadLocalDirect > get:" + threadLocal.get());
System.out.println(Thread.currentThread().getName() + " - threadLocalDirect > ThreadScore.get:" + ThreadScore.get());
threadLocalDirectSub();
}
public void threadLocalDirectSub() {
ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
System.out.println(Thread.currentThread().getName() + " - threadLocalDirectSub > get:" + threadLocal.get());
System.out.println(Thread.currentThread().getName() + " - threadLocalDirectSub > ThreadScore.get:" + ThreadScore.get());
}
-- result
main - threadLocalDirect > get:89
main - threadLocalDirect > get:89
main - threadLocalDirect > ThreadScore.get:91
main - threadLocalDirectSub > get:null
main - threadLocalDirectSub > ThreadScore.get:91
ThreadLocal 변수 사용이 끝난 후에는 remove() method 를 호출해 줘야 하는데, 웹 기반의 애플리케이션에서는 쓰레드를 재사용하기 위해서 ThreadPool 을 사용하는데, ThreadPool 을 사용하면 Thread 가 시작된 후에 그냥 끝나는 것이 아니기 때문에 remove() method 를 사용하여 값을 지워줘야지만 해당 thread 를 다음에 사용할 때 쓰레기 값이 들어 있지 않게 된다.
withInitial(Supplier supplier)
마지막으로 ThreadLocal 의 get() method 를 사용할 때 아직 설정된 값이 없을 경우(set() method 가 호출되기 전) 에 초기값을 supplier 를 통해 지정해도록 해주는 method 이다.
ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> -1);
System.out.println(Thread.currentThread().getName() + " - threadLocalDirectSub > get:" + threadLocal.get());
-- result
main - threadLocalDirectSub > get:-1
'JAVA' 카테고리의 다른 글
| Linux, Docker, Nginx 관련 자주사용하는 명령어 정리 (0) | 2024.02.26 |
|---|---|
| Functional Interface 파고들기 - Predicate, Consumer, Supplier + (0) | 2022.05.02 |
| Functional Interface 파고들기 - Function + (0) | 2022.04.29 |
| Functional Interface 파고들기 (0) | 2022.04.28 |
| JPA - Auditing 과 상속을 통한 공통 속성 공통화 (0) | 2022.03.16 |
댓글