Netty Por qué no sólo tiene que utilizar AtomicXXX, sino más bien utilizar AtomicXXXFieldUpdater para actualizar las variables?

Me puedo concentrar en un mayor intercambio de tecnología

prefacio

Si se lee con cuidado el modelo de programación de subprocesos código fuente Netty, o NIO objeto hilo y el código fuente para crear un grupo de subprocesos, entonces, ciertamente experimentar una cifra similar "AtomicIntegerFieldUpdater", --Netty no dejar de preguntarse por qué no sólo tiene que utilizar un empaquetamiento atómico ordinaria tales como contar las variables?

Con esta pregunta a continuación, profundidad en Netty y JDK código fuente para espiar o dos, la forma de aprender el uso avanzado. Original: Netty Por qué no sólo tiene que utilizar AtomicXXX, sino más bien utilizar AtomicXXXFieldUpdater para actualizar las variables?

operaciones mecanismo implementa la clase Atómica Atómica de JDK

En el JDK, la operación atómica al comienzo de la clase Atómica Hay muchos relacionados con el tipo digital común de Java, el funcionamiento básico tiene un átomo Atómica clase correspondiente, como se muestra a continuación:

clases atómicos son operaciones compatibles con el proceso, se puede utilizar de forma segura cuando se codifica. A continuación átomos AtomicInteger que se utilizan comúnmente clase como un ejemplo, el análisis del mecanismo subyacente para la realización de estos átomos de clases, una ayuda para entender por qué no clase directa átomos Netty. demostración específica utilizada no escritura, presumiblemente Javaer se utilizan o cuántos visto nunca, mirando directamente a AtomicInteger Core Fuente:

. 1  privada  volátil  int valor; // simplificar alguna fuente no básicos 
2  3. // inicialización, se simplifica alguna fuente no subyacente 4. Pública de AtomicInteger ( int la initialValue) {
 5.      Value = la initialValue;
 . 6 }
 . 7 público final int GET () {
 . 8 retorno valor;
 . 9 }
 10 // incrementa en uno, y devuelve el valor anterior de la auto-energizante     . 11 pública final int getAndIncrement () {
 12 es retorno unsafe.getAndAddInt ( el este 
            
        , ValueOffset, 1 );
 13 es  }
 14  // Decremento 1, y devuelve el valor antes del incremento     
15  pública  final  int getAndDecrement () {
 16      retorno unsafe.getAndAddInt ( el este , valueOffset, -1 );
 . 17 }

Arriba, AtomicInteger puede ser hilo valor de tipo int seguro de operación de incremento o decremento. Se puede ver desde el código fuente, los métodos compatibles con el proceso subyacente de la operación se implementan utilizando métodos inseguros, esto es una clase JDK magia, se puede lograr mucho más cerca de la parte inferior de la función, por lo que no es la aplicación Java, pero éstos puede asegurarse de que el subyacente getAndXXX operaciones son hilos de proceso seguro, en relación con el uso específico y los detalles no seguros, puede hacer referencia a este artículo magia clases Java: análisis sintácticos de aplicaciones no seguras (https://tech.meituan.com/2019/02/14/talk-about-java clase -Magic-unsafe.html, pueden no estar directamente abrieron, se puede copiar y pegar en su navegador)

Digresión: Si el objeto AtomicXXX es una medida Tipo ella? Pánico, Java también proporciona una --AtomicReference tipo personalizado atómica clase de operación, es un objetivo de la operación es un objetos genéricos, que puede soportar un tipo personalizado, que no es el método de la subasta inferior, método de operación en función de el paso de parámetros, el siguiente código:

1  // para las operaciones x realizan accumulatorFunction
 2  // accumulatorFunction es una función, es posible que desee hacer por encargo
 3  // devolver el valor anterior 
. 4  pública  final V getAndAccumulate (V x,
 . 5                                  BinaryOperator <V> accumulatorFunction) {
 . 6      // PREV es el valor antiguo, al lado es el nuevo valor 
7.      V PREV, al lado;
 . 8      // giro + CAS garantía puede reemplazar el antiguo valor 
9.      do {
 10          PREV = get ();
 . 11          // realizar una acción personalizada 
12 es          Siguiente = accumulatorFunction.apply ( PREV, X);
 13 es     } , Mientras que (! CompareAndSet (prev, next));
14      de retorno prev;
15 }

 

AtomicXXXFieldUpdater actualización atómica de JDK y sus ventajas

En Java5, las clases de JDK comenzaron átomos proporcionado, por supuesto, que comprende también un átomo actualizador - clases es decir FieldUpdater sufijo, como entero, Long, hay un actualizador atómica tipo personalizado, el total de tres tipos:

Estos átomos actualizador común en una variedad de excelente marco de código abierto, pero los programadores de negocio directamente generales rara vez se utiliza, de hecho, estos átomos pueden también ser usados ​​para actualizar las variables de paquete compartido (volátil se deben modificar las propiedades del objeto) a atómica lograr estas variables compartidas características actualizadas. Estos variable compartida se envasan puede ser una primitiva, también puede ser un tipo de referencia, a continuación, se pregunta: clases han atómicas también proporcionan un conjunto adicional de átomos, ¿por qué se actualiza? 

En pocas palabras, hay dos razones para variables int, por ejemplo, sobre la base de AtomicIntegerFieldUpdater contador atómica lograr, más pequeños que simplemente pasar directamente AtomicInteger lleno variables int, ya que el primero sólo necesita un variables estáticas globales se pueden empaquetar AtomicIntegerFieldUpdater volátiles no estático modificado variables compartidas, y se puede lograr con los átomos de actualizaciones CAS, y lo hacen, por lo que cada uno los objetos subsiguientes de la misma clase sólo necesita compartir este actualizador atómica estática para contadores de objetos de actualización implementados átomos, y los átomos clase para cada objeto de la misma clase están creando un contador + objetos AtomicInteger, esta sobrecarga es obviamente relativamente grande.

Ver el ejemplo siguiente del átomo actualizador JDK, es decir, el JDK BufferedInputStream, la siguiente es la fuente Extraído:

1  pública  clase BufferedInputStream extiende FilterInputStream {
 2      privada  estática  int DEFAULT_BUFFER_SIZE = 8192 ;
3      privada  estática  int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8 ;
4      protegido  volátil  byte buf [];
5      / ** 
6       * actualizador Atómica para proporcionar compareAndSet por buf. Se trata de
 7       * necesario porque se cierra puede ser asíncrona. Utilizamos nullness
 8       * de buf [] como principal indicador de que esta corriente está cerrado. (El
 9      * "En" campo también se anula a cabo en cierre.)
 10       * / 
11      privado  estática  final de 
12          AtomicReferenceFieldUpdater <BufferedInputStream, byte []> bufUpdater =
 13          AtomicReferenceFieldUpdater.newUpdater
 14          (BufferedInputStream. Clase ,   byte []. Clase , "buf" );

Como puede verse, cada objeto contiene una propiedad BufferedInputStream buf, que es las propiedades del objeto, y se modifica la volición, y el embalaje AtomicReferenceFieldUpdater actualizador atómico, nota que el tipo de referencia es una actualización atómica del tipo estático, lo que significa no importa cuántas objetos creados por el usuario BufferedInputStream, que son sólo un átomo en la actualización global se crea, por qué no aquí átomo de AtomicReference clase de propiedad de envasado buf directamente, ya buf es una matriz de bytes, por lo general unos objetos relativamente grandes, Si utiliza envases directa clase atómica, entonces cada uno posterior BufferedInputStream objetos adicionales crearán un objeto de un átomo de clase, consumirá más memoria, una carga más pesada, por lo tanto, JDK uso directo de actualización atómica atómica en lugar de una clase, Netty en el código fuente uso similar es exactamente el mismo.

Otra razón importante es que el uso de actualizador atómica no destruye la estructura original de las variables compartidas, vuelve al ejemplo JDK, fuera buf todavía pueden retener la propiedad matriz original buf objetos, pero más que una modificación volátil, el mundo exterior puede ser directamente esta matriz de bytes para poner en práctica algo de lógica de negocio, y cuando sea necesario también se puede lograr usando actualizador atómica actualizaciones atómicas, puede ser descrito como dos que no se demore, flexibilidad fuerte!

Puede haber un punto de duda necesidad de entender que aunque actualizador atómica es estática, sino que modifica la variable compartida es de hecho todavía la clase de propiedades de los objetos que aún son objetos de cada clase que contiene sólo poseen una sola acción variables, no porque actualizador atómica es estática, afectada de ninguna manera.

Conclusión: La mejor manera de lograr una actualización atómica es ejecutado directamente usando actualizaciones atómicas. Por un lado, es más para ahorrar memoria, por otra parte, no destruye el original variables compartidas, un uso más flexible. Por supuesto, si el requisito de retardo no es tan alto en la escena, entonces usted no tiene que ser el uso tan dura y directa de la clase atómica sobre Aceptar, después de todo tipo simple atómica de codificación, el desarrollo de alta eficiencia, menos propenso a errores.

Netty código fuente del producto, aprender la mejor ejecución de una actualización atómica

He dicho antes, mucha teoría, véase la siguiente sección de código fuente Netty, Netty ver lo elegante que el uso de actualizador atómica. La siguiente es la clase de implementación de Netty NIO porción fuente --SingleThreadEventExecutor hilo se omite y una gran cantidad de código independiente de este análisis:

1  / ** 
2  * clase base abstracta para { @ link s OrderedEventExecutor} 'que ejecutan todas las tareas presentadas en un solo hilo.
3   * / 
4  pública  abstracta  clase SingleThreadEventExecutor extiende AbstractScheduledEventExecutor implementos OrderedEventExecutor {
 5      privada  estática  última  int ST_NOT_STARTED = 1 ;
6      privada  estática  final de  int ST_STARTED = 2 ;
7      privado  estática  final de  int ST_SHUTTING_DOWN = 3;
8      privada  estática  final de  int ST_SHUTDOWN = 4 ;
9      privado  estática  final de  int ST_TERMINATED = 5 ;
10  11 privada estática última AtomicIntegerFieldUpdater <SingleThreadEventExecutor> STATE_UPDATER;
12 privada estática última AtomicReferenceFieldUpdater <SingleThreadEventExecutor, ThreadProperties> PROPERTIES_UPDATER;
13 privado estática final de largo SCHEDULE_PURGE_INTERVAL = TimeUnit.SECONDS.toNanos (1 );
14                       15      estática {
 16          AtomicIntegerFieldUpdater <SingleThreadEventExecutor> actualizador =
 17                  PlatformDependent.newAtomicIntegerFieldUpdater (SingleThreadEventExecutor. Clase , "estado" );
18          Si (actualizador == nula ) {
 19              actualizador = AtomicIntegerFieldUpdater.newUpdater (SingleThreadEventExecutor. Clase , "estado" );
20          }
 21          STATE_UPDATER = actualizador;
22      }
 23  24 privado última cola <Ejecutable>      TaskQueue;
25      privada  última ejecutor Ejecutor;
26      privado  volátil hilo de rosca;
27      privado  volátil  int estado = ST_NOT_STARTED;

Tomado sobre un pequeño fragmento, y eliminar una nota, pueden ver claramente el objeto Thread encapsula Netty JDK constante estática número de estado hilo identificación, un hilo de ejecución, un asíncrono cola de tareas, e identifica las propiedades de estado hilo como estado, que se centran en el estado, esta propiedad es variables comunes compartidos, modificados por la volatilidad, y son embalaje actualizador STATE_UPDATER atómica estática.

下面看NIO线程的启动源码:

. 1      / ** 
2       * método NioEventLoop de roscas de entrada, no se determinará si se ha iniciado el presente hilo NIO
 . 3       * / 
. 4      Privada  void StartThread () {
 . 5          SI (STATE_UPDATER.get ( el este ) == ST_NOT_STARTED) {
 . 6              IF (STATE_UPDATER.compareAndSet ( el este , ST_NOT_STARTED, ST_STARTED)) {
 7.                  doStartThread ();
 . 8              }
 9.          }
 10      }

注释写到了,启动NIO线程之前会做一次是否已经启动的判断,避免重复启动,这个判断逻辑就是前面提到的原子更新器实现的,当本NIO线程实例没有启动时,会做一次CAS计算,注意CAS对应操作系统的一个指令,是原子操作,如果是多个外部线程在启动NIO线程,那么同时只有一个外部线程能启动成功一次,后续的线程不会重复启动这个NIO线程。保证在NIO线程的一次生命周期内,外部线程只能调用一次doStartThread()方法,这样可以实现无锁更新,且没有自旋,性能较好,这里之所以不需要自旋,是因为启动线程就应该是一锤子买卖,启动不成功,就说明是已经启动了,直接跳过,无需重试。

 

En una vuelta para ver el uso de:

En el hilo NIO es elegante (puede ser una excepción) cuando está cerrado, se bucle infinito, combinado con el algoritmo CAS, actualizaciones atómicas el estado actual de la rosca está cerrado NIO en. . . Hay dos consideraciones:

1, y la lógica a partir NIO hilo de rosca de seguridad no es lo mismo, el estado de rosca de actualización debe tener éxito, no es un asunto de una sola, lo que necesita para volver a intentar la vuelta hasta que las operaciones exitosas CAS

2, requiere el uso de variables locales en caché fuera del valor anterior de la variable compartida, para asegurar que el antiguo valor de las operaciones variables compartidas realizadas durante el CAS no se modifica rosca exterior

3. Del mismo modo, la aplicación del CAS antes de cada operación, se debe determinar el valor de la anterior, sólo se actualicen de acuerdo con las condiciones, lo que realmente ejecutar operaciones CAS, o las instrucciones se han actualizado correctamente roscas externas, no hay necesidad de repetir la operación, para mejorar el rendimiento.

 

Al hacerlo, también Netty refleja indirectamente fuente Nerty es realmente muy buena, por lo general el desarrollo de negocios, si hay una escena similar, puede referirse al estudio de estos dos tipos de uso.

 

Resumen de notas de la utilización de actualizador atómica:

1, el envase debe ser modificado variables compartidas volátiles

2, el envase debe ser variables no estática compartidos

3, la rutina debe ser implementado con CAS y comparar su propia lógica de intercambio

Nota lógica 4, un auto-cumplida comparar y de intercambio: si la operación de reparto no de una sola vez al día atómica, debe ser almacenado en caché el valor anterior de la variable compartida externa con las variables locales, las razones específicas puede referirse a: el análisis de rosca modelo de programación Netty (10 ) "multi-hilo medio ambiente, las variables de instancia en variables locales conocimientos de programación", y poner un funcionamiento en bucle para asegurar que la consistencia final.

 

posdata

el blog Dashuai es practicante de aprendizaje permanente, los fabricantes programador, y se centran en la experiencia de trabajo, notas de estudio y la cuota diaria Tucao, incluyendo, pero no limitado a, la industria de Internet, viene a compartir algunos libros electrónicos en formato PDF, información, ayuda empuje en el interior, bienvenido Paizhuan!

 

Supongo que te gusta

Origin www.cnblogs.com/kubixuesheng/p/12650686.html
Recomendado
Clasificación