En Spring Cloud, usamos Hystrix para implementar disyuntores. En ZUUL, los semáforos se usan de forma predeterminada (Hystrix se roscan de forma predeterminada). Podemos usar el aislamiento de subprocesos a través de la configuración.
Al usar el aislamiento de hilos, hay un problema que debe resolverse, es decir, en algunos escenarios comerciales, los datos se pasan en Threads a través de ThreadLocal. Está bien usar semáforos, y proviene de la solicitud, pero el proceso posterior se trata de un hilo.
Cuando el modo de aislamiento está roscado, Hystrix colocará la solicitud en el grupo de subprocesos de Hystrix para su ejecución. En este momento, una solicitud se convertirá en un hilo B, y Threadlocal desaparecerá inevitablemente.
Simulemos este proceso a través de una columna simple:
clase pública CustomThreadLocal {Static ThreadLocal <String> ThreadLocal = new ThreadLocal <> (); public static void main (string [] args) {new Thread (new runnable () {@Override public void run () {CustomThreadLocal.threadLocal.set ("Apes"); new Service (). Call ();}}). Start (); }} Servicio de clase {public void call () {System.out.println ("Servicio:" + Thread.CurrentThread (). GetName ()); System.out.println ("Servicio:" + CustomThreadLocal.threadLocal.get ()); nuevo Dao (). Llame (); }} clase Dao {public void call () { System.out.println("============================================================================================== ================================================================================================================== ================================================================================================================== =========================================================================================================================================================================================== S CustomThreadLocal.threadLocal.get ());Definimos un hilo en la clase principal para pasar datos, luego se crea un hilo, y el método de llamada en el servicio se llama en el subproceso, y se establece un valor en ThreadLocal, y el valor en ThreadLocal se obtiene en el Servicio, y luego se llama al método de llamada en DAO, que también se obtiene en ThreadLocal. Vamos a ejecutarlo para ver el efecto:
Servicio: Thread-0
Servicio: simios y cielo
======================================
Dao: Thread-0
Dao: El mundo del mundo
Puede ver que todo el proceso se ejecuta en el mismo hilo, y el valor en ThreadLocal se ha obtenido correctamente. No hay problema en esta situación.
A continuación, transformamos el programa, realizamos la conmutación de subprocesos y llamamos la llamada en DAO para reiniciar una ejecución de hilo:
clase pública CustomThreadLocal {Static ThreadLocal <String> ThreadLocal = new ThreadLocal <> (); public static void main (string [] args) {new Thread (new runnable () {@Override public void run () {CustomThreadLocal.threadLocal.set ("Apes"); new Service (). Call ();}}). Start (); }} Servicio de clase {public void call () {System.out.println ("Servicio:" + Thread.CurrentThread (). GetName ()); System.out.println ("Servicio:" + CustomThreadLocal.threadLocal.get ()); // nuevo dao (). call (); new Thread (new Runnable () {@Override public void run () {new Dao (). Call ();}}). Start (); }} clase Dao {public void call () { System.out.println ("======================================================================================= ==========================================================================================================================================================================================================================================================================================. ===================================================================================================================================================================================================================. ==========================================================================================================================================================================================================================================================================================. System.out.println ("Dao:" + Thread.CurrentThread (). GetName ());Corre de nuevo para ver el efecto:
Servicio: Thread-0
Servicio: simios y cielo
======================================
Dao: Thread-1
Dao: NULL
Puede ver que esta solicitud fue completada por dos hilos. Todavía puede obtener el valor de ThreadLocal en el servicio. No puede obtenerlo en DAO porque el hilo ha sido cambiado. Este es el problema de que los datos de ThreadLocal se perderán al principio.
Entonces, cómo resolver este problema es realmente muy simple, solo necesita cambiar una línea de código:
static ThreadLocal <String> ThreadLocal = new HereTAblethreadLocal <> ();
Cambie ThreadLocal a HereTablethreadLocal, echemos un vistazo al efecto después de la transformación:
Servicio: Thread-0
Servicio: simios y cielo
======================================
Dao: Thread-1
Dao: El mundo del mundo
El valor se puede obtener normalmente. HereTablethreadLocal es causado por resolver el problema de que ThreadLocal no puede obtener el valor debido a este cambio de rosca.
Para comprender el principio de HeritablethreadLocal, primero debemos comprender el principio de ThreadLocal. Presentemos brevemente el principio de ThreadLocal:
Cada subproceso tiene una propiedad de SubTlocals de Type ThreadLocalMap. La clase ThreadLocalMap es equivalente a un mapa. La clave es ThreadLocal en sí, y el valor es el valor que establecemos.
Implementos de hilo de clase pública Runnable {ThreadLocal.ThreadLocalMap ThreadLocals = null;} Cuando pasamos ThreadLocal.set ("Apes and World");, ponemos un par de valores clave en la propiedad ThreadLocals en este hilo. La clave es el hilo actual, y el valor es el valor que establece.
Public void set (t value) {Thread t = Thread.CurrentThread (); ThreadLocalMap map = getMap (t); if (map! = null) map.set (este, valor); else createMap (t, valor);} Cuando usamos el método ThreadLocal.get (), obtenemos el valor establecido por este hilo en función del hilo actual como la clave.
public t get () {Thread t = Thread.CurrentThread (); ThreadLocalMap map = getMap (t); if (map! = null) {threadlocalmap.entry e = map.getEntry (this); if (e! = null) {@suppleswarnings ("sin verificar") t resultado = (t) e.value; resultado de retorno; }} return setInitialValue ();}A través de la introducción anterior, podemos entender que ThreadLocal puede pasar datos usando Thread.CurrentThread () para obtenerlo, es decir, siempre que esté en el mismo hilo, se puede obtener el valor establecido en el frente.
Si la siguiente operación recrea un subproceso después de que ThreadLocal ha establecido el valor, y Thread.CurrentThread () ha cambiado en este momento, entonces definitivamente no obtendrá el valor que ha establecido antes. Para una reproducción específica de problemas, consulte mi código anterior.
Entonces, ¿por qué está bien HeritableThreadLocal?
La clase HereThablethreadlocal hereda los métodos de TreveLocal y reescrito 3. Al crear un nuevo hilo de instancia de hilo en el hilo actual, estas variables de hilo se pasarán desde el hilo actual a la instancia de nuevo hilo.
La clase pública inheritableThreadLocal <t> extiende ThreadLocal <t> { /** * calcula el valor inicial del niño para esta variable de hilo local * hereditaria * en función del valor del padre en el momento en que se crea el hilo infantil *. Este método se llama desde dentro del hilo de los padres * antes de que se inicie el niño. * <p> * Este método simplemente devuelve su argumento de entrada, y debe anularse * si se desea un comportamiento diferente. * * @param parentValue el valor del hilo principal * @return el valor inicial del hilo infantil */ protegido t childValue (t parentValue) {return parentValue; } /*** Obtenga el mapa asociado con un ThreadLocal. * * @param t el hilo actual */ threadlocalmap getMap (hilo t) {return t.inheritableThreadLocals; } /*** Crear el mapa asociado con un ThreadLocal. * * @param t El hilo actual * @param FirstValue Value para la entrada inicial de la tabla. */ void createMap (Thread t, t FirstValue) {t.inheritableThreadLocals = new ThreadLocalMap (this, FirstValue); }}A través del código anterior, podemos ver que el reescribido de los tres métodos, el valor infantil, GetMap y Createmap. Cuando establecemos el valor en él, el valor se guarda en HereTablethreadLocals, en lugar de los ThreadLocals anteriores.
El punto clave está aquí. ¿Por qué podemos obtener el valor en ThreadLocal en el hilo anterior al crear un nuevo grupo de subprocesos? La razón es que cuando se crea un nuevo subproceso, el HereTablethreadLocals del subproceso anterior se asignará a la HeritableThreadLocals del nuevo subproceso, que realiza la transmisión de datos de esta manera.
El código fuente está inicialmente en el método de inicio de subprocesos, como sigue:
if (parent.inheritablethreadlocals! = null) this.inheritableThreadLocals = ThreadLocal.CreateReRitedMap (parent.inheritableThreadLocals);
CreateRheritedMap de la siguiente manera:
static threadlocalMap createInheritedMap (ThreadLocalMap ParentMap) {return New ThreadLocalMap (ParentMap); }Código de asignación:
Private ThreadLocalMap (ThreadLocalMap ParentMap) {Entry [] ParentTable = ParentMap.Table; int len = parenttable.length; setthreshold (len); tabla = nueva entrada [Len]; for (int j = 0; j <len; j ++) {entrada e = parentTable [j]; if (e! = null) {@SupessWarnings ("sin verificar") ThreadLocal <ject> Key = (ThreadLocal <SPEt>) E.Get (); if (key! = null) {objeto valor = key.childValue (e.value); Entrada c = nueva entrada (clave, valor); int h = key.threadlocalhashcode & (len - 1); while (tabla [h]! = nulo) h = nextIndex (h, len); tabla [h] = c; tamaño ++; }}}}Hasta este punto, a través de HeritablethreadLocals, podemos pasar el valor en el hilo local al niño cuando el hilo principal crea el hilo del niño. Esta característica puede satisfacer la mayoría de las necesidades, pero hay otro problema grave de que si se trata de reutilización de subprocesos, habrá problemas. Por ejemplo, si se trata de reutilización de subprocesos, usará HereTAblethreadLocals en el grupo de subprocesos para pasar los valores, porque HeritableThEltreadLocals solo pasará valores al crear un nuevo hilo. ThreadReuse no hará esta operación. Entonces, para resolver este problema, debe extender la clase de hilo por usted mismo para implementar esta función.
No olvides que estamos haciendo Java. El mundo de código abierto tiene todo lo que necesitas. A continuación recomiendo una biblioteca Java que se haya implementado, que es el código de texto de código abierto de Alibaba.
Dirección de Github: https://github.com/alibaba/transmittable-thread-local
La función principal es resolver el problema de la entrega de valor de ThreadLocal cuando se usa grupos de subprocesos y otros componentes que almacenan en caché, y resolver el problema de la entrega de contexto durante la ejecución asincrónica.
La clase HereTIblethreadLocal de JDK puede completar el valor que pasa del hilo principal al hilo infantil. Sin embargo, para el caso donde se usa el grupo de roscas y otros componentes que caché los roscas, el hilo es creado por el grupo de subprocesos y el hilo se almacena en caché y se usa repetidamente; En este momento, no tiene sentido pasar el valor de Threadlocal de la relación entre padres y hilos. Lo que la aplicación necesita es aprobar el valor de ThreadLocal al enviar la tarea al grupo de subprocesos a la ejecución de la tarea.
Los métodos de uso locales transmitibles-thread se dividen en tres tipos: modificar las clases de implementación del grupo de subprocesos de Java Runnable y llamable.
A continuación, demostremos el método de modificación del grupo de subprocesos. Primero, tomemos un caso anormal, el código es el siguiente:
clase pública CustomThreadLocal {static ThreadLocal <String> ThreadLocal = new HeritableLethreadLocal <> (); static EjecutorService Pool = Ejecutors.NewFixedThreadPool (2); public static void main (string [] args) {for (int i = 0; i <100; i ++) {int j = i; Pool.execute (new Thread (new Runnable () {@Override public void run () {CustomThreadLocal.threadLocal.set ("Ape World"+J); new Service (). Call ();}})); }}} Servicio de clase {public void call () {CustomThreadLocal.pool.execute (new Runnable () {@Override public void run () {new Dao (). Call ();}}); }} clase Dao {public void call () {System.out.println ("Dao:" + CustomThreadLocal.threadLocal.get ()); }}El resultado de ejecutar el código anterior es incorrecto, y la salida es la siguiente:
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
El correcto debe ser de 1 a 100. Debido a la reutilización de hilo, el valor se reemplazará solo si se reemplaza.
A continuación, use transmisible-hilo-local para transformar el código problemático y agregue la dependencia maven de transmisible-hilo local:
<Spendency> <MoupRoD> com.alibaba </groupId> <artifactId> transmittable-thread-local </artifactid> <versión> 2.2.0 </versión> </pendency>
Simplemente modifique 2 lugares, modifique el grupo de subprocesos y reemplace heredableLethreadLocal:
static transmittableThreadLocal <String> ThreadLocal = new TransmittableThreadLocal <> (); static eScutorService Pool = ttlexCutors.gettTlexCuTorService (ejecutors.newfixedThreadPool (2));
Los resultados correctos son los siguientes:
Dao: Ape World 85
Dao: Apes y World 84
Dao: Apes y World 86
Dao: Apes y World 87
Dao: Apes y World 88
Dao: Ape World 90
Dao: Apes y World 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
En este punto, podemos resolver perfectamente la transmisión de datos de Threadlocal en grupos de subprocesos. Los queridos lectores están desconcertados nuevamente. El título no se trata de cómo resolver este problema en Spring Cloud. También encontré este problema en Zuul. La solución ha sido contada a todos. En cuanto a cómo resolver este problema en Zuul, todos deben pensarlo usted mismo. Lo compartiré contigo si tienes tiempo más tarde.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.