Coding Planet
ThreadLocal๊ณผ ThreadLocalUtil ๋ณธ๋ฌธ
|ThreadLocal์ด๋
ThreadLocal์ Java์ ์ค๋ ๋ ๋ก์ปฌ ๋ณ์๋ฅผ ๊ด๋ฆฌํ ์ ์๋๋ก ํ๋ ๊ธฐ๋ฅ์ด๋ค. ์ง๊ธ๊น์ง ๋ณ์๋ค์ ํด๋์ค, ๋ฉ์๋ ๋ ๋ฒจ์์ ๊ด๋ฆฌ๋์๋๋ฐ ์ค๋ ๋๋ณ๋ก ์ ์ฅ๋๊ณ ๊ด๋ฆฌํ ์ ์๋ ๊ฒ์ด๋ค.
์ฆ, ํ ์ค๋ ๋์์ ์ค์ ํ ThreadLocal ๋ณ์์ ๊ฐ์ ๋ค๋ฅธ ์ค๋ ๋์ ๊ณต์ ๋์ง ์์ผ๋ฉฐ, ๊ฐ ์ค๋ ๋๋ ํด๋น ๋ณ์์ ์์ ๋ง์ ๋
๋ฆฝ์ ์ธ ๊ฐ์ ์ ์งํ๊ฒ ๋๋ค. ์ด๋ฅผ ํตํด ์ค๋ ๋ ๊ฐ ๋ฐ์ดํฐ ๊ฒฉ๋ฆฌ๊ฐ ์ด๋ฃจ์ด์ ธ ์ค๋ ๋ ์์ ์ฑ(thread-safety)์ ํ๋ณดํ ์ ์๋ค.
๋ ๊ฐ๋จํ ์ค๋ช ํ์๋ฉด threadLocal๋ณ์๋ฅผ ์ ์ธํ๋ฉด ๋ฉํฐ ์ค๋ ๋ ํ๊ฒฝ์์ ๊ฐ ์ค๋ ๋๋ง๋ค ๋ ๋ฆฝ์ ์ธ ๋ณ์๋ฅผ ๊ฐ์ง๊ฒ ๋๊ณ ๊ฐ ๊ฐ์ get(), set() ๋ฉ์๋๋ฅผ ํตํด ์ ๊ทผํ ์ ์๊ฒ ๋๋ค.
**thread-safety
๋ฉํฐ ์ค๋ ๋ฉ ํ๊ฒฝ์์ ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ๊ฐ์ ์ธ์คํด์ค์ ๋ฉ์๋๋ฅผ ํธ์ถํ๊ฑฐ๋ ๊ฐ์ ์์์ ์ ๊ทผํด๋ ํ๋ก๊ทธ๋จ์ ์คํ ๊ฒฐ๊ณผ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๋์ค๋ ๊ฒ์ ์๋ฏธํ๋ค. ์ฆ, ์ฝ๋๊ฐ ์์ํ ๋๋ก ๋์ํ์ฌ ๋ฐ์ดํฐ์ ์ ํ์ฑ๊ณผ ์ผ๊ด์ฑ์ ์ ์งํ๋ฉฐ, ์๊ธฐ์น ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์๋ ์ํ๋ฅผ ๋งํ๋ค.
|ThreadLocal ์์
public class ThreadLocalExample {
// ThreadLocal ๋ณ์ ์ ์
private static ThreadLocal<String> threadLocal1 = new ThreadLocal<>();
private static ThreadLocal<String> threadLocal2 = new ThreadLocal<>();
public static void main(String[] args) {
// ์ฒซ ๋ฒ์งธ ์ค๋ ๋์์ ThreadLocal ๋ณ์์ ๊ฐ ํ ๋น
Thread thread1 = new Thread(() -> {
threadLocal1.set("Value 1 from Thread 1");
threadLocal2.set("Value 2 from Thread 1");
System.out.println("Thread 1 - ThreadLocal1: " + threadLocal1.get());
System.out.println("Thread 1 - ThreadLocal2: " + threadLocal2.get());
});
// ๋ ๋ฒ์งธ ์ค๋ ๋์์ ThreadLocal ๋ณ์์ ๊ฐ ํ ๋น
Thread thread2 = new Thread(() -> {
threadLocal1.set("Value 1 from Thread 2");
threadLocal2.set("Value 2 from Thread 2");
// ์ ์ ๋๊ธฐํ์ฌ ์ฒซ ๋ฒ์งธ ์ค๋ ๋๊ฐ ๊ฐ์ ์ถ๋ ฅํ๊ณ ๋์ ์ถ๋ ฅํ๋๋ก ํจ
try {
Thread.sleep(100); // 100ms ๋๊ธฐ
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 2 - ThreadLocal1: " + threadLocal1.get());
System.out.println("Thread 2 - ThreadLocal2: " + threadLocal2.get());
});
// ์ค๋ ๋ ์์
thread1.start();
thread2.start();
}
}
๊ฐ ์ฐ๋ ๋์ ๋์ผํ ๋ณ์๋ช ์(threadLocal1, threadLocal2) ๊ฐ์ ์ง์ ํ๋ค. ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ๋ค.
(์ค๋ ๋ ์ค์ผ์ฅด๋ฌ์ ๋ฐ๋ผ ์ค์ ๋ ์ฝ๊ฐ์ ์ฐจ์ด๊ฐ ์์ ์ ์๋ค.)
์ด ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ thread1๊ณผ thread2๊ฐ ๊ฐ๊ฐ ThreadLocal1๊ณผ ThreadLocal2์ ์๋ก ๋ค๋ฅธ ๊ฐ์ ์ ์ฅํ๊ณ , ์ด ๊ฐ๋ค์ด ์ค๋ ๋ ๊ฐ์ ๋ ๋ฆฝ์ ์์ ๋ณด์ฌ์ค๋ค. ๊ฐ ์ค๋ ๋๋ ์์ ์ด ์ค์ ํ ThreadLocal ๋ณ์์ ๊ฐ์ ์ถ๋ ฅํ๋ฉฐ, ๋ค๋ฅธ ์ค๋ ๋์ ๊ฐ์ ์ํฅ์ ๋ฐ์ง ์๋๋ค.
|ThreadLocal ์๋์๋ฆฌ - set(), get()
ThreadLocal์ set() ๊ตฌํ์๋ฆฌ๋ ๋ค์ ์ฝ๋์ ๊ฐ๋ค.
public void set(T value) {
Thread currentThread = Thread.currentThread();
ThreadLocalMap map = getMap(currentThread);
if (map != null) {
map.set(this, value);
} else {
createMap(currentThread, value);
}
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
> set () ๊ตฌํ์๋ฆฌ
- ํ์ฌ ์ค๋ ๋์ ThreadLocalMap์ ์ป๋๋ค. ThreadLocalMap์ ThreadLocal ๋ณ์๋ค์ ๊ฐ์ ์ ์ฅํ๊ธฐ ์ํด ๊ฐ ์ค๋ ๋์ ํ ๋น๋ ๋งต์ด๋ค. ๋ง์ฝ ํ์ฌ ์ค๋ ๋์ ThreadLocalMap์ด ์์ง ์์ผ๋ฉด, ์๋ก์ด ThreadLocalMap์ ์์ฑํ๊ณ ํ์ฌ ์ค๋ ๋์ ํ ๋นํ๋ค.
- ์ป์ด์ง ThreadLocalMap์ ํ์ฌ ThreadLocal ์ธ์คํด์ค๋ฅผ ํค๋ก ํ์ฌ, set ๋ฉ์๋์ ์ ๋ฌ๋ ๊ฐ์ ์ ์ฅํ๋ค. ๋ง์ฝ ์ด ํค์ ํด๋นํ๋ ๊ฐ์ด ์ด๋ฏธ ๋งต์ ์กด์ฌํ๋ค๋ฉด, ์๋ก์ด ๊ฐ์ผ๋ก ๋์ฒด๋๋ค.
> get() ๊ตฌํ์๋ฆฌ
- ํ์ฌ ์ค๋ ๋ ํ๋: Thread.currentThread()๋ฅผ ํธ์ถํ์ฌ ํ์ฌ ์คํ ์ค์ธ ์ค๋ ๋ ๊ฐ์ฒด๋ฅผ ํ๋ํ๋ค.
- ์ค๋ ๋๋ณ ์ ์ฅ์ ์กฐํ: getMap(t)๋ฅผ ํตํด ํ์ฌ ์ค๋ ๋์ ํ ๋น๋ ThreadLocalMap ์ธ์คํด์ค๋ฅผ ์กฐํํ๋ค.
- ๊ฐ ์กฐํ:
- ThreadLocalMap์ด ์กด์ฌํ๋ค๋ฉด, map.getEntry(this)๋ฅผ ํธ์ถํ์ฌ ํ์ฌ ThreadLocal ๊ฐ์ฒด(this)์ ๋ํ ์ ์ฅ๋ ๊ฐ์ ํฌํจํ๋ Entry ๊ฐ์ฒด๋ฅผ ์กฐํํ๋ค. ์ด๋, this๋ ํ์ฌ ThreadLocal ์ธ์คํด์ค๋ฅผ ์ฐธ์กฐํ๋ค.
- Entry ๊ฐ์ฒด๊ฐ ์กด์ฌํ๋ค๋ฉด, ์ด ๊ฐ์ฒด์ value ํ๋์์ ์ค์ ์ ์ฅ๋ ๊ฐ์ ์กฐํํ๋ค. Entry ๊ฐ์ฒด๋ ThreadLocalMap ๋ด๋ถ์์ ThreadLocal ์ธ์คํด์ค์ ์ฐ๊ฒฐ๋ ๊ฐ์ ๊ด๋ฆฌํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ๋ด๋ถ ํด๋์ค.
- ๊ฐ ๋ฐํ:
- ์กฐํํ ๊ฐ์ด ์กด์ฌํ๋ฉด, ์ด ๊ฐ์ ์บ์คํ ํ์ฌ ๋ฐํํ๋ค. ์ฌ๊ธฐ์ @SuppressWarnings("unchecked") ์ ๋ํ ์ด์ ์ ์ด ์บ์คํ ๊ณผ์ ์์ ๋ฐ์ํ ์ ์๋ ํ์ ์์ ์ฑ ๊ฒฝ๊ณ ๋ฅผ ์ต์ ํ๋ค.
- ๋ง์ฝ ThreadLocalMap์ด ์กด์ฌํ์ง ์๊ฑฐ๋, ํ์ฌ ThreadLocal ๊ฐ์ฒด์ ๋ํ Entry๊ฐ ์๋ ๊ฒฝ์ฐ(null์ธ ๊ฒฝ์ฐ), setInitialValue() ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค. ์ด ๋ฉ์๋๋ ThreadLocal ๋ณ์์ ์ด๊ธฐ๊ฐ์ ์ค์ ํ๊ณ ์ด ๊ฐ์ ๋ฐํํ๋ ์ญํ ์ ํ๋๋ฐ, ์ด ์ด๊ธฐ๊ฐ์ ThreadLocal์ initialValue() ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉํ์ฌ ์ ๊ณตํ ์ ์์ผ๋ฉฐ, ๊ธฐ๋ณธ ๊ตฌํ์ null์ ๋ฐํ๋ค.
|ThreadLocalUtil์ด๋
ThreadLocalUtil์ ์๋ฐ์์ ์ฌ์ฉ๋๋ ์ฌ์ฉ์ ์ ์ ์ ํธ๋ฆฌํฐ ํด๋์ค์ด๋ฆ์ผ๋ก. threadlocal์ ์ฌ์ฉํ์ฌ ์ค๋ ๋๋ณ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ๊ด๋ฆฌํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค. ์ ์ ์ค๋ช ํ ๊ฒ์ฒ๋ผ threadlocal์ ๊ฐ ์ค๋ ๋๊ฐ ๊ทธ ์ค๋ ๋ ๋ด๋ถ์์ ์ ์ญ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ฒ ํด์ฃผ๋ฏ๋ก ๋ฐ์ดํฐ์ ์์ ์ฑ์ ๋ณด์ฅํ ์ ์๋ค.
ThreadLocalUtil์ ์ฃผ์๊ธฐ๋ฅ์ ๋ค์๊ณผ ๊ฐ๋ค.
- ์ค๋ ๋๋ณ ๋ฐ์ดํฐ ์ ์ฅ๊ณผ ์ ๊ทผ: ThreadLocalUtil์ ํตํด ๊ฐ ์ค๋ ๋์์๋ง ์ ๊ทผ ๊ฐ๋ฅํ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ , ํ์ํ ๋ ํด๋น ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ฒ ์กฐํํ ์ ์๋ค. ์ด๋ ์ค๋ ๋ ๊ฐ์ ๋ฐ์ดํฐ ์ถฉ๋์ ๋ฐฉ์งํ๊ณ ์ค๋ ๋ ์์ ์ฑ์ ๋์ธ๋ค.
- ์ฌ์ฉ์ ์ธ์ ๊ด๋ฆฌ: ์น ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ฌ์ฉ์์ ์ธ์ ์ ๋ณด๋ ์ธ์ฆ ์ ๋ณด์ ๊ฐ์ ์ค์ํ ์ ๋ณด๋ฅผ ThreadLocal์ ์ฌ์ฉํ์ฌ ๊ด๋ฆฌํ ์ ์๋ค. ์ด๋ฅผ ํตํด ํ์ฌ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ์ค๋ ๋์์ ์ฌ์ฉ์์ ์ธ์ ์ ๋ณด๋ฅผ ์ฝ๊ฒ ์ ๊ทผํ๊ณ ๊ด๋ฆฌํ ์ ์๋ค.
- ์์ ๋ฐ์ดํฐ ์ ์ฅ: ๊ณ์ฐ ์ค๊ฐ ๊ฒฐ๊ณผ๋ ๋ฉ์๋ ๊ฐ์ ์ ๋ฌํด์ผ ํ๋ ์์ ๋ฐ์ดํฐ๋ฅผ ์ค๋ ๋๋ณ๋ก ์ ์ฅํ๊ธฐ ์ํด ์ฌ์ฉํ ์ ์๋ค. ์ด๋ฌํ ์ฉ๋๋ก ThreadLocalUtil์ ์ฌ์ฉํ๋ฉด ๋ฉ์๋์ ๋งค๊ฐ๋ณ์๋ฅผ ์ค์ด๊ณ ์ฝ๋์ ๊ฐ๋ ์ฑ์ ๋์ผ ์ ์๋ค.
|ThreadLocalUtil ์์
์๋๋ ThreadLocalUtil ์ ์ฌ์ฉํ์ฌ ์ค๋ ๋๋ณ๋ก ์ฌ์ฉ์ ์์ด๋๋ฅผ ์ ์ฅํ๋ ๊ฐ๋จํ ์์์ด๋ค.
ThreadLocalUtil ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ์ค๋ ๋์์ ์ฌ์ฉ์ ID๋ฅผ ์ค์ ํ๊ณ ํ์ํ ๋๋ง๋ค ์์ ํ๊ฒ ์ ๊ทผํ ์ ์๋ค. ๋ค๋ง ์ค๋ ๋ ์์ ์ด ์๋ฃ๋๋ฉด clear() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํด์ผํ๋ค.
public class ThreadLocalUtil {
private static final ThreadLocal<String> userId = new ThreadLocal<>();
public static void setUserId(String id) {
userId.set(id);
}
public static String getUserId() {
return userId.get();
}
public static void clear() {
userId.remove();
}
}
์๋์ฒ๋ผ ๋ก๊ทธ์ธ ์ฑ๊ณต์, ์ฌ์ฉ์ ID๋ฅผ ThreadLocalUtil์ ์ ์ฅํ๋๋ก ํ๊ณ ํ์ํ ๊ณณ์์ ThreadLocalUtil์ ์ฌ์ฉํ์ฌ ํ์ฌ ์ธ์ ์ ์ฌ์ฉ์ ID๋ฅผ ๊ฐ์ ธ์ ์ฌ์ฉํ ์ ์๋ค.
// ์ฌ์ฉ์ ๋ก๊ทธ์ธ ์ ์ฌ์ฉ์ ID๋ฅผ ThreadLocalUtil์ ์ ์ฅํ๋ ์์
public void onUserLogin(String userId) {
// ์ฌ์ฉ์ ID๋ฅผ ThreadLocalUtil์ ์ ์ฅ
ThreadLocalUtil.set(ThreadLocalUtil.KEY.sessUserId, userId);
}
// ThreadLocalUtil๋ก๋ถํฐ ํ์ฌ ์ธ์
์ ์ฌ์ฉ์ ID๋ฅผ ๊ฐ์ ธ์ ์ ์ฅํ๋ ์์
public void someMethod() {
// ThreadLocalUtil์์ ์ฌ์ฉ์ ID ๊ฐ์ ธ์ค๊ธฐ
String sessUserID = (String) ThreadLocalUtil.get(ThreadLocalUtil.KEY.sessUserId);
// ๊ฐ์ ธ์จ ์ฌ์ฉ์ ID ์ฌ์ฉ (์: ์ฌ์ฉ์ ID ํ์ธ, ๋ก๊ทธ ์ถ๋ ฅ ๋ฑ)
System.out.println("Current Session User ID: " + sessUserID);
}