2010-02-03 29 views
9

La lectura de este DZone article sobre la concurrencia de Java Me preguntaba si el siguiente código:Java volátil pregunta variables


    private volatile List list; 
    private final Lock lock = new ReentrantLock(); 

    public void update(List newList) { 
     ImmutableList l = new ImmutableList().addAll(newList); 
     lock.lock(); 
     list = l; 
     lock.unlock(); 
    } 

    public List get() { 
     return list; 
    } 

es equivalente a:


    private volatile List list; 

    public void update(List newList) { 
     ImmutableList l = new ImmutableList().addAll(newList); 
     list = l; 
    } 

    public List get() { 
     return list; 
    } 

El try {} finally {} bloque se omitió para brevedad. Supongo que la clase ImmutableList es una estructura de datos verdaderamente inmutable que contiene sus propios datos, como el proporcionado en la biblioteca de google-collections. Dado que la variable de la lista es volátil y, básicamente, lo que está sucediendo es una copia al vuelo, ¿no es seguro omitir el uso de bloqueos?

+0

Creo que ambos deben comportarse exactamente lo mismo, pero depende de la aplicación de la 'ImmutableList'. Me esperaba que al llamar 'addAll()' en una 'ImmutableList' lanzaría una excepción, por lo que nunca se usaría el bloqueo. –

Respuesta

6

En este ejemplo muy específico, creo que estaría bien sin bloqueo en la reasignación variable.

En general, creo que es mejor usar un AtomicReference en lugar de una variable volátil ya que los efectos de consistencia de la memoria son los mismos y la intención es mucho más clara.

0

Creo que el comportamiento de sincronización predeterminado de volátil no garantiza el comportamiento ReentrantLock, por lo que podría ayudar con el rendimiento. De lo contrario, creo que está bien.

1

Después de volver a leer este sí, son equivalentes.

+0

¿Cuál es el problema con otro hilo que hace una copia de newList antes de bloquear la referencia a la lista? – Kevin

+0

@Clint siguiendo la pregunta de Kevin, dado que soy local para el método y la actualización para la lista está protegida, ¿un hilo que llame a get() aún no obtendría un resultado consistente? – teto

+0

@Teto sí. La lista de variables miembro no se está modificando, solo se está actualizando la referencia. – Kevin

4

Sí, ambas muestras de código se comportan de la misma manera en un entorno concurrente. Los campos volátiles son , por lo que después de que un hilo llame a update(), que reemplaza la lista con una nueva lista, get() en todos los otros hilos devolverá la nueva lista.

Pero si tiene código que utiliza de esta manera:

list = get() 
list = list.add(something) // returns a new immutable list with the new content 
update(list) 

entonces no funcionará como se espera en cualquiera de los ejemplos de código (si dos hilos hacen que, en paralelo, a continuación, los cambios realizados por uno de ellos puede ser sobrescrito por el otro). Pero si solo un hilo está actualizando la lista, o el nuevo valor no depende del valor anterior, entonces no hay problema.

+0

get() devuelve una ImmutableList, como indiqué en la descripción del problema, intentar modificarlo solo generará una excepción. – teto

+0

Siempre es posible crear una nueva lista inmutable que tenga los elementos de la antigua lista inmutable más algunos más: vea en mi comentario cómo el método add() devuelve una nueva lista. Así es como se hace en la programación funcional. (Si su ejemplo usa google-collections 'ImmutableList, entonces puede que no tenga dicha operación, pero todas las bibliotecas del lenguaje de programación funcional sí lo tienen.) –

+0

El artículo original [actual] actualiza la lista. Esta es parte de la razón por la cual la sincronización en colecciones similares a las de los gustos raramente hace lo que usted desea./El ejemplo en el artículo era lo suficientemente simple para ser reemplazado fácilmente por un ciclo de cas. –

1

Si hablamos de tiempos y visibilidad de la memoria. Una lectura volátil es muy cercana al tiempo que lleva hacer una lectura normal. Entonces si haces get() mucho, entonces hay poca diferencia. El tiempo que se tarda en realizar una escritura volátil es de aproximadamente 1/3 de tiempo para adquirir y liberar un bloqueo. Entonces su segunda sugerencia es un poco más rápida.

La visibilidad de memoria como la mayoría de las personas que se sugiere es equivalente, es decir, cualquier lectura antes de la adquisición de bloqueo ocurre antes de cualquier escritura después de la adquisición de bloqueo similar a cualquier lectura antes de una lectura inestable ocurre antes de cualquier escritura posterior

1

los siguientes criterios debe cumplirse para las variables volátiles para proporcionar la seguridad de hilo deseada:

  1. Las escrituras en la variable no dependen de su valor actual.
  2. La variable no participa en invariantes con otras variables.

Dado que tanto se cumplen aquí - código es hilo de seguridad