Heim >Java >javaLernprogramm >Was sind Thread-lokale Variablen?

Was sind Thread-lokale Variablen?

零下一度
零下一度Original
2017-07-21 14:34:262354Durchsuche

Der genauere Name von ThreadLocal, übersetzt ins Chinesische, sollte lauten: lokale Thread-Variable.

Was nützt das Ding bzw. warum gibt es so etwas? Lassen Sie mich zunächst erklären, dass Mitgliedsvariablen während der gleichzeitigen Programmierung tatsächlich Thread-unsicher sind, wenn keine Verarbeitung erfolgt. Dies ist offensichtlich nicht möglich, und wir wissen auch, dass das Schlüsselwort volatile keine Thread-Sicherheit garantiert. Sicher. In einem Fall müssen wir also eine solche Bedingung erfüllen: Die Variable ist dieselbe, aber jeder Thread verwendet denselben Anfangswert, das heißt, er verwendet eine neue Kopie derselben Variablen. In diesem Fall ist ThreadLocal beispielsweise sehr nützlich. Da wir wissen, dass DAO ein Singleton ist, ist sein Attribut Connection keine Thread-sichere Variable. Und jeder unserer Threads muss es verwenden, und jeder verwendet sein eigenes. In diesem Fall löst ThreadLocal dieses Problem besser.

Wir analysieren dieses Problem aus der Perspektive des Quellcodes.

Definieren Sie zunächst ein 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);
            }
        }
    }
}

Auf diese Weise wird die gleiche Verbindung verwendet , aber jede Verbindung ist neu und eine Kopie derselben Verbindung.

Was ist also der Implementierungsmechanismus?

1. Jedes Thread-Objekt verwaltet intern eine ThreadLocalMap.

/* ThreadLocal values pertaining to this thread. This map is maintained
 * by the ThreadLocal class. */ThreadLocal.ThreadLocalMap threadLocals = null;

2. ) Rufen Sie zuerst den aktuellen Thread und dann das ThreadLocalMap-Objekt des aktuellen Threads ab. Wenn es nicht leer ist, nehmen Sie den Wert von ThreadLocal heraus, andernfalls initialisieren Sie ihn.

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. Wenn wir die set()-Methode aufrufen, ist es sehr üblich, den Wert in ThreadLocal festzulegen.

4. Zusammenfassung: Wenn wir die get-Methode aufrufen, gibt es tatsächlich einen ThreadLocal in jedem aktuellen Thread. Jede Erfassung oder Einstellung ist eine Operation für ThreadLocal und von anderen Threads getrennt.

5. Anwendungsszenario: ThreadLocal eignet sich am besten, wenn viele Threads dasselbe Objekt mehrmals verwenden müssen und das Objekt denselben Initialisierungswert haben muss.

6. Egal wie viel ich sage, es ist besser, sich den Quellcode anzusehen, um es klarer zu machen. Wenn Sie sich den Quellcode ansehen möchten, handelt es sich um eine schwache Referenz und eine Karte. Diese beiden Stellen sind schwache Referenzen von a.Java, das heißt, die umschlossenen (referenzierten) Referenzen werden zerstört GC. Objekt, dieses ThreadLocal als Schlüssel kann zerstört werden, aber solange die von uns definierte Klasse nicht entladen wird, verweist die starke Referenz von tl immer auf dieses ThreadLocal und wird niemals von GC entfernt. b. Ähnlich wie HashMap.

Das obige ist der detaillierte Inhalt vonWas sind Thread-lokale Variablen?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn