2009-09-23 8 views
92

¿Cuál es la diferencia entre los métodos lazySet y set de AtomicInteger? El documentation no tiene mucho que decir sobre lazySet:AtomicInteger lazySet vs. set

establece el tiempo al valor dado.

Parece que el valor almacenado no se establecerá inmediatamente en el valor deseado, sino que se programará en algún momento en el futuro. Pero, ¿cuál es el uso práctico de este método? ¿Algún ejemplo?

Respuesta

95

Citado directamente desde Bug 6275329:

Como probablemente la última poco JSR166 seguimiento de Mustang, añadimos un método "lazySet" a las clases atómicos (AtomicInteger, AtomicReference, etc). Este es un método de nicho que a veces es útil cuando se ajusta el código usando estructuras de datos sin bloqueo. La semántica es que la escritura está garantizada para no ser reordenada con ninguna escritura previa , pero puede reordenarse con operaciones posteriores (o, de manera equivalente, podría no ser visible para otros hilos) hasta alguna otra escritura volátil o acción de sincronización ocurre).

El caso de uso principal es para anular campos de nodos en las estructuras de datos no bloqueantes con el único fin de evitar retención de basura a largo plazo; se aplica cuando es inofensivo si otros subprocesos ven valores no nulos por un tiempo, pero desea para asegurarse de que las estructuras sean eventualmente GCables. En tales casos , puede obtener un mejor rendimiento al evitar los costos de la escritura volátil nula. Hay unos pocos casos de uso de en esta línea para atómicos no basados ​​en referencias , por lo que el método es compatible con todas las clases AtomicX.

Para las personas que les gusta pensar en estas operaciones en términos de barreras a nivel de máquina en multiprocesadores comunes, lazySet proporciona una barrera precedente almacén de la tienda (que es ya sea un no-op o muy barato en plataformas actuales) , pero no barrera de carga de tienda (que suele ser la parte costosa de una escritura volátil).

+4

¿Alguien podría atontarlo para el resto de nosotros? :( – Gaurav

+9

Lazy es la versión no volátil (por ejemplo, no se garantiza que el cambio de estado sea visible para todos los hilos que tienen el alcance 'Atomic *'). – yawn

+45

Lo que no entiendo es por qué javadoc es tan pobre al respecto –

2

Re: intento de embrutecer -

Se puede pensar en esto como una manera de tratar a un campo volátil como si no fuera volátil para una tienda en particular (por ejemplo: ref = null;) operación.

Eso no es exactamente exacto, pero debería ser suficiente para poder tomar una decisión entre "OK, realmente no me importa" y "Hmm, déjame pensar en eso por un momento".

3

Aquí está mi entendimiento, corrígeme si estoy equivocado: Puede pensar en lazySet() como "semi" volátil: es básicamente una variable no volátil en términos de lectura por otros hilos, es decir, el valor establecido por LazySet puede no ser visible para otros hilos. Pero se vuelve volátil cuando se produce otra operación de escritura (puede ser de otros hilos). El único impacto de lazySet que puedo imaginar es compareAndGet.Entonces, si usa lazySet(), get() de otros subprocesos puede obtener el valor anterior, pero compareAndGet() siempre tendrá el nuevo valor ya que es una operación de escritura.

+0

¿no quieres decir 'compareAndSet'? –

8

Una discusión más amplia de los orígenes y la utilidad de lazySet y la putOrdered subyacente se puede encontrar aquí: http://psy-lob-saw.blogspot.co.uk/2012/12/atomiclazyset-is-performance-win-for.html

En resumen: lazySet es una escritura volátil débil en el sentido de que actúa como un almacén de la tienda y no una cerca de la tienda de carga. Esto se reduce a lazySet siendo JIT compilado a una instrucción MOV que no puede ser reordenada por el compilador en lugar de la instrucción significativamente más cara utilizada para un conjunto volátil.

Al leer el valor siempre termina haciendo una lectura volátil (con un Atomic * .get() en cualquier caso).

lazySet le ofrece a un único escritor un mecanismo de escritura volátil consistente, es decir, es perfectamente legítimo que un escritor use lazySet para incrementar un contador, múltiples hilos que incrementen el mismo contador tendrán que resolver las escrituras que compiten usando CAS, que es exactamente lo que sucede bajo las tapas de Atomic * para incAndGet.

+0

exactamente, ¿por qué no podemos decir que esta es una simple barrera 'StoreStore', pero * no * una' StoreLoad'? – Eugene

11

lazySet se puede utilizar para la comunicación entre subprocesos, porque xchg es atómico, en cuanto a la visibilidad, cuando el proceso de subproceso de escritor modifica una ubicación de línea de caché, el procesador del subproceso lo verá en la siguiente lectura, porque el protocolo de coherencia de caché intel cpu garantizará que LazySet funcione, pero la línea de caché se actualizará en la próxima lectura, una vez más, la CPU tiene que ser lo suficientemente moderna.

http://sc.tamu.edu/systems/eos/nehalem.pdf Para Nehalem, que es una plataforma multi-procesador, los procesadores tienen la capacidad de “espiar” (espiar) el bus de direcciones de otro procesador de accesos a la memoria del sistema y de sus cachés internos. Usan esta habilidad de espionaje para mantener sus cachés internos consistentes tanto con la memoria del sistema como con las cachés en otros procesadores interconectados. Si un procesador detecta que otro procesador intenta escribir en una ubicación de memoria almacenada en caché en estado Compartido, el procesador invalidará su bloque de caché obligándolo a realizar un relleno de línea de caché la próxima vez que acceda a la misma memoria ubicación.

Oracle JDK punto de acceso para x86 cpu arquitectura->

lazySet == unsafe.putOrderedLong == xchg rw (instrucción asm que sirven como una barrera suave cuesta 20 ciclos de CPU nehelem Intel)

en x86 (x86_64) dicha barrera es mucho más económica que la de Volatile o AtomicLong getAndAdd,

En un productor, un escenario de cola de consumidor, la barrera blanda xchg puede forzar la línea de códigos antes de lazySet (secuencia + 1) para cadena de producción que sucederá ANTES de cualquier código de cadena de consumo que consumirá (trabajará) los nuevos datos, de Por supuesto, el hilo del consumidor deberá verificar atómicamente que la secuencia del productor se incrementó exactamente en uno utilizando un conjunto de parámetros comparar (comparar) y secuencia (secuencia, secuencia + 1).

que remontar después de que el código fuente hotspot podrá encontrar la asignación exacta de la lazySet al código de CPP: http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/prims/unsafe.cpp Unsafe_setOrderedLong -> Definición SET_FIELD_VOLATILE -> OrderAccess: release_store_fence. Para x86_64, OrderAccess: release_store_fence se define como el uso de la instrucción xchg.

Se puede ver cómo se define exactamente en JDK7 (Doug Lea está trabajando en algunas cosas nuevas para JDK 8): http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/4fc084dac61e/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp

también puede utilizar los índices de desarrollo humano a desmontar el conjunto del código lazySet en acción.

Hay otra pregunta relacionada: Do we need mfence when using xchg

+3

Es difícil entender lo que está obteniendo aquí. ¿Puedes aclarar tu punto? –

+3

"lazySet == unsafe.putOrderedLong == xchg rw (instrucción asm que sirve como una barrera blanda que cuesta 20 ciclos en nehelem intel cpu) en x86 (x86_64) una barrera de este tipo es mucho más económica que la volatilidad o AtomicLong getAndAdd "-> Esto no es verdad según mi leal saber y entender. LazySet/putOrdered es un MOV para una dirección, por lo que el libro de cocina JMM lo describe como no-operativo en x86. –

6

Desde el Concurrent-atomic package summary

lazySet tiene los efectos de memoria de la escritura (asignación) una variable volátil, excepto que permite reordenamientos con posterior (pero no anterior) acciones de memoria que no imponen restricciones de reordenamiento con escrituras ordinarias no volátiles. Entre otros contextos de uso, lazySet puede aplicarse al anular, por el bien de la recolección de basura, una referencia a la que nunca se accede de nuevo.

Si eres curioso acerca de lazySet entonces lo debes a ti mismo otras explicaciones demasiado

La memoria efectos de accesos y actualizaciones de las atómicas general siguen las reglas para las sustancias volátiles, como se indica en la sección 17.4 del Java ™ Especificación de idioma.

obtener tiene los efectos de memoria de leer una variable volátil.

conjunto tiene los efectos de memoria de escribir (asignar) una variable volátil.

lazySet tiene los efectos de memoria de la escritura (asignación) una variable volátil, excepto que permite reordenamientos con acciones posteriores de memoria (pero no anteriores) que por sí mismas no imponen restricciones reordenación con las escrituras no volátiles ordinarios. Entre otros contextos de uso , se puede aplicar lazySet al anular, por el bien de la recolección de basura , una referencia a la que nunca se accede de nuevo.

weakCompareAndSet atómicamente lee y condicionalmente escribe una variable pero no crea ningún ordenamientos sucede-antes, por lo que proporciona hay garantías con respecto a las lecturas anteriores o posteriores y escribe de cualquier variable que no sean el blanco de la weakCompareAndSet. compareAndSet y todas las demás operaciones de lectura y actualización como getAndIncrement tienen los efectos de memoria de leer y escribir variables volátiles.