sincronizados productor metodos example consumidor atomicas java multithreading variables synchronization atomicity

productor - variables atomicas java



Operaciones atómicas y multihilo. (6)

Recientemente estuve leyendo un tutorial, en el que encontré una declaración que dice ...

"La especificación del lenguaje Java garantiza que leer o escribir una variable es una operación atómica (a menos que la variable sea de tipo long o double ). Las variables de operaciones de tipo long o double son solo atómicas si se declaran con la palabra clave volatile ".

AtomicInteger o AtomicLong que proporciona métodos como getAndDecrement() , getAndIncrement() y getAndSet() que son atómicos.

Me confundí un poco con la declaración anterior ... ¿podría aclarar cuándo usar las clases AtomicInteger o AtomicLong ?


Atómico significa que la operación se completa sin ninguna posibilidad de que algo suceda entre ellos. p.ej. getAndDecrement (), en AtomicInteger, garantiza que la variable se devuelve Y disminuye al mismo tiempo.

Si no fuera una operación atómica, existiría la posibilidad de que el valor disminuyera (por ejemplo, de 3 a 2), luego modificado por otro hilo (por ejemplo, cambiándolo de 2 a 5), ​​luego devuelto como 5.


Creo que lo que significa es que la operación larga y de doble lectura es atómica y la operación de escritura es atómica. Pero una lectura + escritura no es atómica.

volatile long num; num = num+1

Lo anterior no es seguro para hilos. Allí leer y escribir son dos operaciones separadas. Se garantiza que cada uno de ellos es atómico, pero la expresión completa no lo es.

Para hacer que el subproceso sea seguro, necesitarías usar un AtomicLong y usar la función getAndIncrement.


Hacer a = 28 (con a ser un int ) es una operación atómica. Pero hacer a++ no es una operación atómica porque requiere una lectura del valor de a, un incremento y una escritura del resultado. Como resultado, si usó a++ para implementar un contador seguro para subprocesos, podría tener dos subprocesos que leen el valor al mismo tiempo (26 por ejemplo), luego incrementarlo y escribirlo al mismo tiempo, dando como resultado 27 como resultado, en lugar de 28.

AtomicInteger resuelve este problema proporcionando operaciones atómicas como las que enumeró. En mi ejemplo, usaría incrementAndGet() por ejemplo, lo que garantizaría que el valor final sea 28 y no 27.


Necesita un AtomicInteger si necesita leer una variable y escribir un resultado dependiendo del valor de lectura . Por ejemplo, i++ lee i (por ejemplo, 3 ) y escribe i+1 (por ejemplo, 4 ). Mientras tanto, un hilo puede ser interrumpido, y otros tres subprocesos incrementan i también. Ahora que regresamos, en realidad tengo el valor 6 pero nuestro hilo aún escribe 4 , según lo que leyó de antemano.

AtomicInteger.getAndIncrement garantiza que no se interrumpa y, por lo tanto, siempre aumente correctamente. Además, el resultado siempre se descarga en la memoria , mientras que un i no volátil no se puede descargar en la memoria. En este caso, es posible que otros subprocesos ni siquiera vean los cambios.


Utiliza int o long en función del límite superior / inferior del rango de números con los que está tratando. Por favor, no mezcle el comportamiento no atómico de largo con AtomicLong. Lo que haya escrito anteriormente es correcto, pero probablemente esté mezclando ambos conceptos. AtomicXXX es más útil en los casos en los que está realizando operaciones de tipo "comparar y configurar". Por ejemplo, incluso cuando int puede modificarse / leerse de forma atómica, el siguiente código será incorrecto en un entorno multiproceso:

int i =10 .. .. .. if(i == 10) i++;

en un entorno de subprocesos múltiples, dos subprocesos pueden acceder a este código de forma atómica y el valor actualizado de i, lo que hace que tenga un estado consistente. Para lidiar con tales situaciones, normalmente guarda el código "if (i == 10) i ++;" Con bloque sincronizado. Sin embargo, la clase AtomicInteger proporciona la API para lograr tales cosas sin utilizar bloques sincronizados que son más lentos. Igual es el caso de las API de AtmoicLong.


se requiere la atomicidad de una operación cuando se muta una variable. haciendo int a = 10; es una operación atómica pero no es la que te dará el problema. las operaciones de dar problemas generalmente son mutantes como a++ o a = a + 2; y así.

La especificación de Java garantiza que "leer" y "escribir" son operaciones atómicas, no sus combinaciones. por lo tanto, una operación que ''lee, agrega 1 y luego escribe el resultado'' no es atómica según la especificación. dichas operaciones se denominan operaciones compuestas y, por lo general, deben ser atómicas en el contexto de su uso en nuestro código.

Los tipos atómicos ayudan a resolver este problema. el uso de incrementAndget () en un tipo atómico hace que ''lea, agregue 1 y luego vuelva a escribir el resultado y lea el nuevo resultado'' una única operación atómica en contexto para la seguridad de subprocesos.

Espero que esto ayude. Por cierto, debería leer este artículo ( http://walivi.wordpress.com/2013/08/24/concurrency-in-java-a-beginners-introduction/ ) sobre los conceptos básicos de concurrencia y subprocesos. explica estas cosas maravillosamente