concurrent clase atomicinteger java atomic

clase - Java-usando AtomicInteger vs Static int



java 8 concurrent collections (7)

Al usar varios subprocesos, he aprendido a usar variables estáticas siempre que quiero usar un contador al que se accederá mediante varios subprocesos.

Ejemplo:

static int count=0; Luego más tarde en el programa lo uso como count++; .

Hoy encontré algo llamado AtomicInteger y también aprendí que es Thread safe y podría usar uno de sus métodos llamado getAndInrement() para lograr el mismo efecto.

¿Alguien podría ayudarme a entender sobre el uso de static atomicInteger versus static int count ?


"static" hace que la var sea a nivel de clase. Eso significa que, si define "conteo estático int" en una clase, sin importar cuántas instancias haya creado de la clase, todas las instancias usan el mismo "conteo". Si bien AtomicInteger es una clase normal, solo agrega protección de sincronización.


AtomicInteger es para obtener e incrementar como un proceso atómico. Se puede pensar como un secuenciador en la base de datos. Proporciona métodos de utilidad para incrementar, disminuir valores delta int.

static int puede causar problemas si obtiene un contador y luego lo procesa y luego lo actualiza. AtomicInteger lo hace fácilmente, pero no puede usarlo si tiene que actualizar el contador basándose en los resultados del procesamiento.


Con AtomicInteger el incrementAndGet() garantiza ser atómico.
Si usa count++ para obtener el valor anterior, no se garantiza que sea atómico.

Algo que omití de tu pregunta, y fue afirmado por otra respuesta, static no tiene nada que ver con el subprocesamiento.


Creo que no hay garantía de ver en la count++ el valor más nuevo. count++ debe leer el valor de count . Otro Thread puede haber escrito un nuevo valor para count pero almacenó su valor en la memoria caché local del Thread , es decir, no se descarga en la memoria principal. Además, su Thread , que lee el count , no tiene garantía de leer desde la memoria principal, es decir, actualizar desde la memoria principal. synchronize gurantes que.


Estoy de acuerdo con la respuesta de @Kumar.

La volatilidad no es suficiente, tiene algunas implicaciones para el orden de la memoria, pero no garantiza la atomicidad de ++.

Lo realmente difícil de la programación de subprocesos múltiples es que los problemas pueden no aparecer en una cantidad razonable de pruebas. Escribí un programa para demostrar el problema, pero tiene hilos que no hacen más que incrementar los contadores. Aun así, los conteos están dentro del 1% de la respuesta correcta. En un programa real, en el que los subprocesos tienen otro trabajo que hacer, puede haber una probabilidad muy baja de que dos subprocesos hagan el ++ lo suficientemente cerca como para mostrar simultáneamente el problema. La corrección de varios hilos no puede ser probada, tiene que ser diseñada en.

Este programa realiza la misma tarea de conteo utilizando un int estático simple, un int volátil y un AtomicInteger. Solo el AtomicInteger siempre obtiene la respuesta correcta. Una salida típica en un multiprocesador con 4 núcleos de doble hilo es:

count: 1981788 volatileCount: 1982139 atomicCount: 2000000 Expected count: 2000000

Aquí está el código fuente:

import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class Test { private static int COUNTS_PER_THREAD = 1000000; private static int THREADS = 2; private static int count = 0; private static volatile int volatileCount = 0; private static AtomicInteger atomicCount = new AtomicInteger(); public static void main(String[] args) throws InterruptedException { List<Thread> threads = new ArrayList<Thread>(THREADS); for (int i = 0; i < THREADS; i++) { threads.add(new Thread(new Counter())); } for (Thread t : threads) { t.start(); } for (Thread t : threads) { t.join(); } System.out.println("count: " + count + " volatileCount: " + volatileCount + " atomicCount: " + atomicCount + " Expected count: " + (THREADS * COUNTS_PER_THREAD)); } private static class Counter implements Runnable { @Override public void run() { for (int i = 0; i < COUNTS_PER_THREAD; i++) { count++; volatileCount++; atomicCount.incrementAndGet(); } } } }


static int counter le daría un resultado inconsistente en un entorno multithreaded , a menos que haga que el contador sea volatile o que el bloque de incremento esté synchronized .

En el caso de automic , ofrece programación thread-safe lock-free en variables individuales.

Más detalle en automic''s y link


- AtomicInteger se utiliza para realizar la operación atómica sobre un entero , es una alternativa cuando no desea utilizar una palabra clave synchronized .

- El uso de un elemento volatile en un campo no atómico dará un resultado inconsistente.

int volatile count; public void inc(){ count++ }

- static hará que una variable sea compartida por todas las instancias de esa clase , pero aún así producirá un resultado inconsistente en un entorno de subprocesos múltiples.

Así que intente esto cuando esté en un entorno multihilo:

1. Siempre es mejor seguir la Regla de Brian:

Cada vez que escribimos una variable que está próxima a ser leída por otro hilo, o cuando estamos leyendo una variable que está escrita solo por otro hilo, debe estar sincronizada. Los campos compartidos deben hacerse privados, haciendo que los métodos de lectura y escritura / sentencias atómicas estén sincronizados.

2. La segunda opción es usar las Atomic Classes , como AtomicInteger, AtomicLong, AtomicReference, etc.