중국어로 번역된 ThreadLocal의 더 정확한 이름은 스레드 로컬 변수입니다.
이건 무슨 용도인지, 저런 건 왜 있는 걸까요? 먼저 동시 프로그래밍 중에 멤버 변수는 처리가 수행되지 않으면 실제로 스레드에 안전하지 않다는 점을 설명하겠습니다. 각 스레드는 동일한 변수를 작동하며 이는 분명히 불가능하며 휘발성 키워드가 스레드 보안을 보장하지 않는다는 것도 알고 있습니다. 안전한. 따라서 어떤 경우에는 다음과 같은 조건을 충족해야 합니다. 즉, 변수는 동일하지만 각 스레드는 동일한 초기 값을 사용합니다. 즉, 동일한 변수의 새 복사본을 사용합니다. 이 경우 ThreadLocal은 매우 유용합니다. 예를 들어 DAO의 데이터베이스 연결은 DAO가 싱글톤이므로 해당 속성 Connection은 스레드로부터 안전한 변수가 아닙니다. 그리고 각 스레드는 이를 사용해야 하며, 각각은 자체 스레드를 사용합니다. 이 경우 ThreadLocal은 이 문제를 더 잘 해결합니다.
이 문제를 소스코드 관점에서 분석합니다.
먼저 ThreadLocal을 정의합니다.
ThreadLocal<Connection> tl = ThreadLocal<Connection> Connection initConn = = DriverManager.getConnection("url, name and password"=( ==
package java.lang;import java.lang.ref.*;import java.util.concurrent.atomic.AtomicInteger;public class ThreadLocal<T> { private final int threadLocalHashCode = nextHashCode(); private static AtomicInteger nextHashCode =new AtomicInteger();private static final int HASH_INCREMENT = 0x61c88647;private static int nextHashCode() {return nextHashCode.getAndAdd(HASH_INCREMENT); }protected T initialValue() {return null; }public ThreadLocal() { }public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T)e.value; }return setInitialValue(); }private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);if (map != null) map.set(this, value);elsecreateMap(t, value);return value; }public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);if (map != null) map.set(this, value);elsecreateMap(t, value); } public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }ThreadLocalMap getMap(Thread t) {return t.threadLocals; }void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {return new ThreadLocalMap(parentMap); }T childValue(T parentValue) {throw new UnsupportedOperationException(); }static class ThreadLocalMap {static class Entry extends WeakReference<ThreadLocal> {/** The value associated with this ThreadLocal. */Object value; Entry(ThreadLocal k, Object v) {super(k); value = v; } }private static final int INITIAL_CAPACITY = 16;private Entry[] table;private int size = 0;private int threshold; // Default to 0private void setThreshold(int len) { threshold = len * 2 / 3; }private static int nextIndex(int i, int len) {return ((i + 1 < len) ? i + 1 : 0); }private static int prevIndex(int i, int len) {return ((i - 1 >= 0) ? i - 1 : len - 1); }ThreadLocalMap(ThreadLocal firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY];int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); }private ThreadLocalMap(ThreadLocalMap parentMap) { Entry[] parentTable = parentMap.table;int len = parentTable.length; setThreshold(len); table = new Entry[len];for (int j = 0; j < len; j++) { Entry e = parentTable[j];if (e != null) { ThreadLocal key = e.get();if (key != null) { Object value = key.childValue(e.value); Entry c = new Entry(key, value);int h = key.threadLocalHashCode & (len - 1);while (table[h] != null) h = nextIndex(h, len); table[h] = c; size++; } } } }private Entry getEntry(ThreadLocal key) {int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i];if (e != null && e.get() == key)return e;elsereturn getEntryAfterMiss(key, i, e); }private Entry getEntryAfterMiss(ThreadLocal key, int i, Entry e) { Entry[] tab = table;int len = tab.length;while (e != null) { ThreadLocal k = e.get();if (k == key)return e;if (k == null) expungeStaleEntry(i);elsei = nextIndex(i, len); e = tab[i]; }return null; }private void set(ThreadLocal key, Object value) {Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len-1);for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal k = e.get();if (k == key) { e.value = value;return; }if (k == null) { replaceStaleEntry(key, value, i);return; } } tab[i] = new Entry(key, value);int sz = ++size;if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }private void remove(ThreadLocal key) { Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len-1);for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {if (e.get() == key) { e.clear(); expungeStaleEntry(i);return; } } }private void replaceStaleEntry(ThreadLocal key, Object value, int staleSlot) { Entry[] tab = table;int len = tab.length; Entry e;int slotToExpunge = staleSlot;for (int i = prevIndex(staleSlot, len); (e = tab[i]) != null; i = prevIndex(i, len))if (e.get() == null) slotToExpunge = i;for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { ThreadLocal k = e.get();if (k == key) { e.value = value; tab[i] = tab[staleSlot]; tab[staleSlot] = e;if (slotToExpunge == staleSlot) slotToExpunge = i; cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);return; }if (k == null && slotToExpunge == staleSlot) slotToExpunge = i; }tab[staleSlot].value = null; tab[staleSlot] = new Entry(key, value);if (slotToExpunge != staleSlot) cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); }private int expungeStaleEntry(int staleSlot) { Entry[] tab = table;int len = tab.length;tab[staleSlot].value = null; tab[staleSlot] = null; size--; Entry e;int i;for (i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { ThreadLocal k = e.get();if (k == null) { e.value = null; tab[i] = null; size--; } else {int h = k.threadLocalHashCode & (len - 1);if (h != i) { tab[i] = null;while (tab[h] != null) h = nextIndex(h, len); tab[h] = e; } } }return i; }private boolean cleanSomeSlots(int i, int n) {boolean removed = false; Entry[] tab = table;int len = tab.length;do { i = nextIndex(i, len); Entry e = tab[i];if (e != null && e.get() == null) { n = len; removed = true; i = expungeStaleEntry(i); } } while ( (n >>>= 1) != 0);return removed; }private void rehash() { expungeStaleEntries();// Use lower threshold for doubling to avoid hysteresisif (size >= threshold - threshold / 4) resize(); }private void resize() { Entry[] oldTab = table;int oldLen = oldTab.length;int newLen = oldLen * 2; Entry[] newTab = new Entry[newLen];int count = 0;for (int j = 0; j < oldLen; ++j) { Entry e = oldTab[j];if (e != null) { ThreadLocal k = e.get();if (k == null) { e.value = null; // Help the GC} else {int h = k.threadLocalHashCode & (newLen - 1);while (newTab[h] != null) h = nextIndex(h, newLen); newTab[h] = e; count++; } } } setThreshold(newLen); size = count; table = newTab; }private void expungeStaleEntries() { Entry[] tab = table;int len = tab.length;for (int j = 0; j < len; j++) { Entry e = tab[j];if (e != null && e.get() == null) expungeStaleEntry(j); } } } }
이런 방식으로 동일한 연결이 사용되지만 각 연결은 새 연결이고 동일한 연결의 복사본입니다.
그럼 구현 메커니즘은 무엇인가요?
1. 각 Thread 객체는 내부적으로 ThreadLocalMap을 유지합니다. 이러한 ThreadLocal 맵은 여러 ThreadLocal을 저장할 수 있습니다
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ThreadLocal.ThreadLocalMap threadLocals = null;
2. get() 메서드를 호출하면 먼저 현재 스레드를 가져온 다음 ThreadLocalMap으로 이동합니다. 현재 스레드의 객체가 비어 있지 않으면 ThreadLocal의 값을 꺼내고, 그렇지 않으면 초기화는 ThreadLocal의 값을 설정하는 것입니다.
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T)e.value; }return setInitialValue(); }
3. set() 메서드를 호출할 때 값을 ThreadLocal에 설정하는 것이 매우 일반적입니다.
4. 요약: get 메소드를 호출하면 실제로 각 현재 스레드에 ThreadLocal이 있습니다. 각 획득 또는 설정은 ThreadLocal에 대한 작업이며 다른 스레드와 별개입니다.
5. 응용 시나리오: ThreadLocal은 많은 스레드가 동일한 객체를 여러 번 사용해야 하고 객체가 동일한 초기화 값을 가져야 하는 경우에 사용하기에 가장 적합합니다.
6. 사실 아무리 말하더라도 더 명확하게 하려면 소스 코드를 보는 것이 더 좋습니다. 소스 코드를 보려면 WeakReference와 Map이 포함됩니다. 이 두 곳을 이해해야 합니다. 이 두 가지는 a.Java의 약한 참조입니다. 즉, 래핑된 참조는 도중에 파괴됩니다. GC.Object, 키인 이 threadLocal은 파괴될 수 있지만 우리가 정의한 클래스가 언로드되지 않는 한 tl의 강력한 참조는 항상 이 ThreadLocal을 참조하며 gc에 의해 제거되지 않습니다. b. HashMap과 유사합니다.
위 내용은 스레드 지역 변수란 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!