In der Federwolke verwenden wir Hytrix, um Leistungsschalter zu implementieren. In Zuul werden Semaphoren standardmäßig verwendet (Hystrix wird standardmäßig getroffen). Wir können die Thread -Isolation durch Konfiguration verwenden.
Bei Verwendung der Thread -Isolation gibt es ein Problem, das gelöst werden muss, dh in einigen Geschäftsszenarien werden Daten in Threads über ThreadLocal übergeben. Es ist in Ordnung, Semaphoren zu verwenden, und es stammt aus der Anfrage, aber der nachfolgende Prozess geht alles um einen Thread.
Wenn der Isolationsmodus überlegt ist, stellt Hytrix die Anforderung zur Ausführung in den Hystrix -Thread -Pool ein. Zu diesem Zeitpunkt wird eine Anfrage zu einem Thread B, und ThreadLocal verschwindet zwangsläufig.
Lassen Sie uns diesen Vorgang durch eine einfache Spalte simulieren:
public class CustomThreadLocal {static ThreadLocal <String> ThreadLocal = new ThreadLocal <> (); public static void main (String [] args) {neuer Thread (new Runnable () {@Override public void run () {customThreadlocal.threadlocal.set ("apes"); new service (). call ();}}). start (); }} class Service {public void call () {System.out.println ("service:" + thread.currentThread (). getName ()); System.out.println ("Service:" + CustomThreadLocal.ThreadLocal.get ()); New DAO (). Call (); }} class dao {public void call () { System.out.println("============================================================================================== =====================================================ieben =====================================================ieben =====================================================ieben CustomTheadLocal.ThreadLocal.get ());Wir definieren einen ThreadLocal in der Hauptklasse, um Daten zu übergeben, und dann wird ein Thread erstellt, und die Aufrufmethode im Dienst wird im Thread aufgerufen, und ein Wert wird in ThreadLocal festgelegt, und der Wert in ThreadLocal wird im Dienst erhalten, und dann wird die Anrufmethode in DAO aufgerufen, die auch in ThreadLocal erhalten wird. Lassen Sie es uns ausführen, um den Effekt zu sehen:
Service: Thread-0
Dienst: Affen und Himmel
=======================================
DAO: Thread-0
DAO: Die Welt der Welt
Sie können sehen, dass der gesamte Prozess im selben Thread ausgeführt wird und der Wert in ThreadLocal korrekt erhalten wurde. In dieser Situation gibt es kein Problem.
Als nächstes transformieren wir das Programm, führen Thread -Switching durch und rufen den Anruf in DAO auf, um eine Thread -Ausführung neu zu starten:
public class CustomThreadLocal {static ThreadLocal <String> ThreadLocal = new ThreadLocal <> (); public static void main (String [] args) {neuer Thread (new Runnable () {@Override public void run () {customThreadlocal.threadlocal.set ("apes"); new service (). call ();}}). start (); }} class Service {public void call () {System.out.println ("service:" + thread.currentThread (). getName ()); System.out.println ("Service:" + CustomThreadLocal.ThreadLocal.get ()); // New DAO (). CALL (); neuer Thread (new Runnable () {@Override public void run () {new DAO (). call ();}}). start (); }} class dao {public void call () { System.out.println("=================================================================================== ===========================================================ieben ============================================================ieben ===========================================================ieben System.out.println ("dao:" + thread.currentThread (). GetName ());Laufen Sie erneut, um den Effekt zu sehen:
Service: Thread-0
Dienst: Affen und Himmel
=======================================
DAO: Thread-1
DAO: NULL
Sie können sehen, dass diese Anfrage von zwei Threads abgeschlossen wurde. Sie können immer noch den Wert von ThreadLocal im Dienst erhalten. Sie können es nicht in DAO bekommen, weil der Thread umgeschaltet wurde. Dies ist das Problem, dass die Daten von ThreadLocal am Anfang verloren gehen.
Wie Sie dieses Problem lösen können, ist also eigentlich sehr einfach. Sie müssen nur eine Codezeile ändern:
static ThreadLocal <String> ThreadLocal = new inheritabletHeadLocal <> ();
Ändern Sie ThreadLocal in die InheritableTheadLocal. Schauen wir uns den Effekt nach der Transformation an:
Service: Thread-0
Dienst: Affen und Himmel
=======================================
DAO: Thread-1
DAO: Die Welt der Welt
Der Wert kann normal erhalten werden. InheritablethreadLocal wird durch Lösen des Problems verursacht, dass ThreadLocal den Wert aufgrund dieser Thread -Switching nicht erhalten kann.
Um das Prinzip der inheritableTheadLocal zu verstehen, müssen wir zunächst das Prinzip des Threadlokals verstehen. Lassen Sie uns kurz das Prinzip von ThreadLocal vorstellen:
Jeder Thread verfügt über eine Threadlocals -Eigenschaft vom Typ ThreadLocalMap. Die ThreadLocalMap -Klasse entspricht einer Karte. Der Schlüssel ist ThreadLocal selbst und der Wert ist der Wert, den wir gesetzt haben.
public class Thread implementiert runnable {ThreadLocal.ThreadlocalMap Threadlocals = null;} Wenn wir ThreadLocal.set ("Affen und Welt") übergeben, setzen wir ein Schlüsselwertpaar in die Threadlocals-Eigenschaft in diesen Thread ein. Der Schlüssel ist der aktuelle Thread und der Wert ist der Wert, den Sie festgelegt haben.
public void set (t value) {thread t = thread.currentThread (); ThreadLocalMap map = getMap (t); if (map! = null) map.set (this, Wert); sonst CreateMap (t, Wert);} Wenn wir die ThreadLocal.get () -Methode verwenden, erhalten wir den Wert, der von diesem Thread basierend auf dem aktuellen Thread als Schlüssel festgelegt wurde.
public t get () {Thread t = thread.currentThread (); ThreadLocalMap map = getMap (t); if (map! if (e! Rückgabeergebnis; }} return setInitialValue ();}Durch die obige Einführung können wir verstehen, dass ThreadLocal Daten durch Verwenden von Thread.CurrentThread () übergeben kann, um sie zu erhalten, dh, solange es sich im selben Thread befindet, kann der vorne festgelegte Wert erhalten werden.
Wenn der nächste Operation einen Thread nachgebaut hat, nachdem der ThreadLocal den Wert festgelegt hat, und Thread.CurrentThread () zu diesem Zeitpunkt geändert hat, werden Sie definitiv nicht den zuvor festgelegten Wert erhalten. Für eine spezifische Reproduktion von Problemen finden Sie in meinem obigen Code.
Warum ist inheritableTheadlocal OK?
Die InheritablethreadLocal -Klasse erbt ThreadLocal und umgeschriebene 3 Methoden. Beim Erstellen eines neuen Thread -Instanz -Threads im aktuellen Thread werden diese Threadvariablen vom aktuellen Thread an die neue Threadinstanz übergeben.
Die öffentliche Klasse InheritableTheadLocal <T> erweitert ThreadLocal <T> { /** * den Anfangswert des Kindes für diese vererbbare Thread-Local * -Variable als Funktion des Werts des Elternteils zum Zeitpunkt des Erstellens des Kindes * -Threads. Diese Methode wird innerhalb des übergeordneten * Threads aufgerufen, bevor das Kind gestartet wird. * <p> * Diese Methode gibt lediglich ihr Eingabargument zurück und sollte überschrieben werden *, wenn ein anderes Verhalten erwünscht ist. * * @Param ParentValue Der Wert des übergeordneten Threads * @return Der Anfangswert des untergeordneten Threads */ geschützt t ChildValue (t ParentValue) {return parentValue; } /*** Holen Sie die Karte, die einem ThreadLocal zugeordnet ist. * * @param t Der aktuelle Thread */ threadLocalMap getMap (Thread t) {return t.inheritabletReadlocals; } /*** Erstellen Sie die Karte, die einem ThreadLocal zugeordnet ist. * * @param t Der aktuelle Thread * @param FirstValue -Wert für den ersten Eintrag der Tabelle. */ void createMap (Thread t, t FirstValue) {t.inheritableTheadlocals = new ThreadLocalMap (this FirstValue); }}Durch den obigen Code können wir sehen, dass inheritablethreadlocal die drei Methoden ChildValue, GetMap und CreateMap umgeschrieben hat. Wenn wir den Wert darin einstellen, wird der Wert anstelle der vorherigen Threadlocals in Inheritabletheadlocals gespeichert.
Der entscheidende Punkt ist hier. Warum können wir beim Erstellen eines neuen Threadpools den Wert im Threadlocal im vorherigen Thread erhalten? Der Grund dafür ist, dass beim Erstellen eines neuen Threads die Inheritabletheadlocals des vorherigen Threads dem Inheritabletheadlocals des neuen Threads zugeordnet werden, der auf diese Weise die Datenübertragung realisiert.
Der Quellcode befindet sich zunächst in der Thread -Init -Methode wie folgt:
if (parent.inheritablethreadlocals! = null) this.inheritablethreadlocals = ThreadLocal
CreateInheritedMap wie folgt:
static threadLocalMap createInheritedMap (ThreadLocalMap parentMap) {return New ThreadLocalMap (parentMap); }Zuweisungscode:
private threadLocalMap (ThreadLocalMap parentMap) {Eintrag [] parentTable = parentmap.table; int len = parentTable.length; SetThreshold (Len); Tabelle = neuer Eintrag [Len]; für (int j = 0; j <len; j ++) {Eintrag e = parentTable [j]; if (e! = null) {@Suppresswarnings ("deaktiviert") ThreadLocal <Obge. if (key! Eintrag c = neuer Eintrag (Schlüssel, Wert); int h = key.threadlocalHashCode & (len - 1); while (table [h]! = null) h = nextIndex (h, len); Tabelle [H] = C; Größe ++; }}}}Bis zu diesem Zeitpunkt können wir durch Inheritablethreadlocals den Wert in lokaler Angaben zum untergeordneten Thread übergeben, wenn der übergeordnete Thread den untergeordneten Thread erstellt. Diese Funktion kann die meisten Bedürfnisse erfüllen, aber es gibt ein anderes ernstes Problem, dass es Probleme geben wird, wenn es sich um eine Wiederverwendung von Threads handelt. Wenn es sich beispielsweise um Wiederverwendung von Threads handelt, verwendet es Inheritabletheadlocals im Thread -Pool, um Werte zu übergeben, da die Inheritabletheadlocals nur Werte übergeben, wenn ein neuer Thread erstellt wird. ThreeReuse wird diese Operation nicht ausführen. Um dieses Problem zu lösen, müssen Sie die Thread -Klasse selbst erweitern, um diese Funktion zu implementieren.
Vergessen Sie nicht, dass wir Java machen. Die Open -Source -Welt hat alles, was Sie brauchen. Im Folgenden empfehle ich eine Java-Bibliothek, die implementiert wurde, nämlich Alibabas Open-Source-Sendable-Thread-Local.
GitHub-Adresse: https://github.com/alibaba/transmittable-thread-local
Die Hauptfunktion besteht darin, das Problem der ThreadLocal -Wert -Lieferung bei Verwendung von Threadpools und anderen Komponenten zu lösen, die Threads zwischenstrichen, und das Problem der Kontextabgabe während der asynchronen Ausführung zu lösen.
JDKs inheritableTheadLocal -Klasse kann die Wertschöpfung des übergeordneten Threads an den untergeordneten Thread vervollständigen. Für den Fall, in dem der Thread -Pool verwendet wird, und andere Komponenten, die Threads zwischen sich bringen, wird der Thread durch den Thread -Pool erstellt und der Faden zwischengespeichert und wiederholt verwendet. Zu diesem Zeitpunkt ist es bedeutungslos, den ThreadLocal-Wert der Eltern-Kind-Thread-Beziehung zu übergeben. Was die Anwendung benötigt, ist tatsächlich, den ThreadLocal -Wert zu übergeben, wenn die Aufgabe an den Thread -Pool an die Aufgabenausführung übermittelt wird.
Die Methoden zur Nutzung von Sendable-thread-lokalen Nutzungen sind in drei Typen unterteilt: Modifizieren
Lassen Sie uns als nächstes die Modifikationsmethode des Threadpools demonstrieren. Lassen Sie uns zunächst einen abnormalen Fall nehmen, der Code lautet wie folgt:
public class CustomThreadLocal {static ThreadLocal <String> ThreadLocal = new inHeritableTheadLocal <> (); statischer ExecutorService Pool = Executors.NewFixedThreadpool (2); public static void main (String [] args) {für (int i = 0; i <100; i ++) {int j = i; pool.execute (neuer Thread (new Runnable () {@Override public void run () {CustomTheadLocal.ThreadLocal.set ("ape World"+j); new Service (). call ();}})); }}} class Service {public void call () {CustomThreadLocal.pool.execute (new Runnable () {@Override public void run () {new DAO (). call ();}}); }} class dao {public void call () {System.out.println ("dao:" + customThreadlocal.threadlocal.get ()); }}Das Ergebnis des Ausführens des oben genannten Code ist falsch und die Ausgabe ist wie folgt:
DAO: Ape World 99
DAO: Ape World 99
DAO: Ape World 99
DAO: Ape World 99
DAO: Ape World 99
DAO: Ape World 99
DAO: Ape World 99
DAO: Ape World 99
DAO: Ape World 99
DAO: Ape World 99
DAO: Ape World 99
DAO: Ape World 99
DAO: Ape World 99
Die richtige sollte von 1 bis 100 liegen. Aufgrund der Wiederverwendung von Gewinnen wird der Wert nur dann ersetzt, wenn er ersetzt wird.
Verwenden Sie als Nächstes den problematischen Code übertragbar-thread-lokal und fügen Sie die Maven-Abhängigkeit von Transmittable-Thread-Local hinzu:
<Depopenty> <gruppe> com.alibaba </Groupid> <artifactId> Transmittable-thread-local </artifactId> <version> 2.2.0 </Version> </abhängig>
Ändern Sie einfach 2 Stellen, ändern Sie den Thread -Pool und ersetzen Sie InheritabletheadLocal:
static transmungabletReadLocal <String> ThreadLocal = new TransmmittabletheadLocal <> (); statischer Ausführenderservicepool = TTLExecutors.gettTlexEcutorService (Executors.NewFixedThreadpool (2));
Die korrekten Ergebnisse sind wie folgt:
DAO: APE WORLD 85
DAO: Affen und Welt 84
DAO: Affen und Welt 86
DAO: Affen und Welt 87
DAO: Affen und Welt 88
DAO: Ape World 90
DAO: Affen und Welt 89
DAO: Ape World 91
DAO: APE WORLD 93
DAO: APE WORLD 92
DAO: APE WORLD 94
DAO: APE WORLD 95
DAO: Ape World 97
DAO: APE WORLD 96
DAO: APE WORLD 98
DAO: Ape World 99
Zu diesem Zeitpunkt können wir die Übertragung von ThreadLocal -Daten in Thread -Pools perfekt lösen. Liebe Leser sind wieder verwirrt. Im Titel geht es nicht darum, dieses Problem in der Frühlingswolke zu lösen. Ich fand dieses Problem auch in Zuul. Die Lösung wurde allen mitgeteilt. Wie Sie dieses Problem in Zuul lösen können, muss jeder selbst darüber nachdenken. Ich werde es mit Ihnen teilen, wenn Sie später Zeit haben.
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.