์๋ฐ์์ ์ค๋ ๋๋ ์ค์ง ์์ ๋ง์ด ์ ๊ทผํด์ ์ฝ๊ณ ์ธ ์ ์๋ ๋ก์ปฌ ๋ณ์ ์ ์ฅ์ ThreadLocal
์ ์ ๊ณตํ๋ค.
๊ฐ ์ค๋ ๋๋ ๊ณ ์ ํ ThreadLocal
๊ฐ์ฒด๋ฅผ ์์ฑ์ผ๋ก ๊ฐ์ง๊ณ ์์ผ๋ฉฐ ThreadLocal
์ ์ค๋ ๋ ๊ฐ ๊ฒฉ๋ฆฌ๋์ด ์๋ค.
์ค๋ ๋๋ ThreadLocal
์ ์ ์ฅ๋ ๊ฐ์ ํน์ ํ ์์น๋ ์์ ์ ์๊ด์์ด ์ด๋์์๋ ์ ์ญ๋ณ์์ฒ๋ผ ์ ๊ทผํด์ ์ฌ์ฉํ ์ ์๋ค.
์ฃผ๋ก ๋ชจ๋ ์ค๋ ๋๊ฐ ๊ณตํต์ ์ผ๋ก ์ฒ๋ฆฌํด์ผ ํ๋ ๊ธฐ๋ฅ์ด๋ ๊ฐ์ฒด๋ฅผ ์ ์ดํด์ผ ํ๋ ์ํฉ์์ ์ค๋ ๋๋ง๋ค ๋ค๋ฅธ ๊ฐ์ ์ ์ฉํด์ผ ํ๋ ๊ฒฝ์ฐ์ ์ฌ์ฉํ๋ค. (์ธ์ฆ ์ฃผ์ฒด ๋ณด๊ด, ํธ๋์ญ์
์ ํ, ๋ก๊ทธ ์ถ์ ๊ธฐ ๋ฑ)
public class Thread implements Runnable {
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
}
์ค๋ ๋๋ ThreadLocal์ ์๋ ThreadLocalMap
๊ฐ์ฒด๋ฅผ ์์ ์ threadLocals ์์ฑ์ ์ ์ฅํ๋ค.
์ค๋ ๋ ์์ฑ ์ threadLocals ๊ธฐ๋ณธ ๊ฐ์ null์ด๋ฉฐ ThreadLocal์ ๊ฐ์ ์ ์ฅํ ๋ ThreadLocalMap์ด ์์ฑ๋๊ณ threadLocals์ ์ฐ๊ฒฐ๋๋ค.
ThreadLocalMap์ ์ค๋ ๋๋ง๋ค ํญ์ ์๋กญ๊ฒ ์์ฑ๋์ด ์ค๋ ๋ ์คํ์ ์ ์ฅ๋๊ธฐ ๋๋ฌธ์ ๊ทผ๋ณธ์ ์ผ๋ก ์ค๋ ๋๊ฐ ๋ฐ์ดํฐ ๊ณต์ ๊ฐ ๋ ์ ์๊ณ ๋์์ฑ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์๋๋ค.
๊ทธ๋ฌ๋ ์ค๋ ๋ ํ์ ์ฌ์ฉํด์ ์ค๋ ๋๋ฅผ ์ด์ฉํ๋ค๋ฉด ๋ฐ๋์ ThreadLocal์ ์ ์ฅ๋ ๊ฐ์ ์ญ์ ํด ์ฃผ์ด์ผ ํ๋ค.
์ค๋ ๋ ํ์ ์ค๋ ๋๋ฅผ ์ฌ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ์ด์ ์ค๋ ๋์์ ThreadLocal์ ์ ์ฅ๋ ๊ฐ์ ์ญ์ ํ์ง ์๊ณ ์ฌ์ฌ์ฉํ๊ฒ ๋๋ค๋ฉด ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
public class ThreadLocal<T> {
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();
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
map.set(this, value);
} else {
createMap(t, value);
}
if (this instanceof TerminatingThreadLocal) {
TerminatingThreadLocal.register((TerminatingThreadLocal<?>) this);
}
return value;
}
}
ThreadLocal์ Thread์ ThreadLocalMap์ ์ฐ๊ฒฐํ์ฌ ์ค๋ ๋ ์ ์ฉ ์ ์ฅ์๋ฅผ ๊ตฌํํ๊ณ ์๋๋ฐ ์ด๊ฒ์ด ๊ฐ๋ฅํ ์ด์ ๋ ๋ฐ๋ก Thread.currentThread
๋ฅผ ์ฐธ์กฐํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
Thread.currentThread()
๋ ํ์ฌ ์คํ์ค์ ์ค๋ ๋ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ ๊ฒ์ผ๋ก์ CPU๋ ์ค์ง ํ๋์ ์ค๋ ๋๋ง ํ ๋น๋ฐ์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ ํ์ฌ ์คํ ์ค์ธ ์ค๋ ๋์ ๋ก์ปฌ ๋ณ์๋ฅผ ์ ์ฅํ๊ฑฐ๋ ์ฐธ์กฐํ ์ ์๊ฒ ๋๋ค.
ThreadLocal์์ ํ์ฌ ์ค๋ ๋๋ฅผ ์ฐธ์กฐํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์๋ค๋ฉด ์ค๋ ๋๋ฅผ ์๋ณํ ์ ์์ ๊ฒ์ด๋ค. ๋๋ฌธ์ Thread.currentThread()
๋ ThreadLocal์ ์ค์ํ ์๋ณ ๊ธฐ์ค์ด ๋๋ค.
InheritableThreadLocal
์ ThreadLocal์ ํ์ฅ ๋ฒ์ ์ผ๋ก์ ๋ถ๋ชจ ์ค๋ ๋๋ก๋ถํฐ ์์์ค๋ ๋๋ก ๊ฐ์ ์ ๋ฌํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๋ค.
๋ถ๋ชจ ์ค๋ ๋๊ฐ InheritableThreadLocal
๋ณ์์ ๊ฐ์ ์ค์ ํ๋ฉด, ํด๋น ๋ถ๋ชจ ์ค๋ ๋๋ก๋ถํฐ ์์ฑ๋ ์์ ์ค๋ ๋๋ค์ ๋ถ๋ชจ์ ๊ฐ์ ์์๋ฐ๊ฒ ๋๋ค.
์์ ์ค๋ ๋๊ฐ ์์๋ฐ์ ๊ฐ์ ๋ณ๊ฒฝํ๋๋ผ๋ ๋ถ๋ชจ ์ค๋ ๋์ ๊ฐ์๋ ์ํฅ์ ์ฃผ์ง ์๋๋ค.
class Thread implements Runnable {
private Thread(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
...
Thread parent = currentThread(); // main Thread
...
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); // main Thread์ ThreadLocalMap์ ๋ณต์ฌ
...
}
}
class ThreadLocal<T> {
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
return new ThreadLocalMap(parentMap);
}
}
- [์๋ฐ ๋์์ฑ ํ๋ก๊ทธ๋๋ฐ [๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ Part.1]](https://www.inflearn.com/course/%EC%9E%90%EB%B0%94-