2010-03-26 22 views
9

Tengo algunas preguntas sobre la asignación de Java.Problemas de asignación Java - ¿Esto es atómico?

  • Cuerdas

Tengo una clase:

public class Test { 
private String s; 

public synchronized void setS(String str){ 
    s = s + " - " + str; 
} 

public String getS(){ 
    return s; 
} 
} 

estoy usando "sincronizado" en mi organismo, y evitar que en mi captador, porque en mi aplicación, hay toneladas de datos que se obtienen y muy pocas configuraciones. La configuración debe estar sincronizada para evitar inconsistencias. Mi pregunta es: ¿conseguir y establecer una variable atómica? Es decir, en un entorno multiproceso, Thread1 está a punto de establecer la variable s, mientras que Thread2 está a punto de obtener "s". ¿Hay alguna forma en que el método getter pueda obtener algo diferente al antiguo valor de s o al nuevo valor de s (supongamos que tenemos solo dos hilos)? En mi aplicación no es un problema obtener el nuevo valor, y no es un problema obtener el anterior. ¿Pero podría obtener algo más?

  • ¿Qué pasa con la obtención y colocación de HashMap?

teniendo en cuenta esto:

public class Test { 
     private Map<Integer, String> map = Collections.synchronizedMap(new HashMap<Integer, String>()); 

     public synchronized void setMapElement(Integer key, String value){ 
     map.put(key, value); 
     } 

     public String getValue(Integer key){ 
     return map.get(key); 
     } 
} 

está poniendo y conseguir atómica? ¿Cómo maneja HashMap poniendo un elemento en él? ¿Quita primero el valor anterior y pone el ahora? ¿Podría obtener un valor diferente al anterior o nuevo?

¡Gracias de antemano!

+0

+1 para especificar que los lectores no necesitan ver el último valor absoluto. Por supuesto, eso definitivamente debe documentarse en el código de producción. –

Respuesta

6

En el primer caso, String pasa a ser seguro para la publicación insegura (en el "nuevo" Modelo de memoria de Java (JMM)), por lo que está bien.

No es volatile teóricamente hay algún problema con no tener un valor actualizado, pero el significado de la actualización no está claro. Podría reemplazar el bloqueo con un bucle compare-sand-swap (CAS), pero eso probablemente no le daría mucha ganancia en el rendimiento, ya sea que el candado haya sido disputado o no.

En el caso de HashMap, un mapa no sincronizado no es seguro de leer si hay otro hilo escribiendo en él, incluso un único hilo de escritor. De hecho, se ha encontrado que esto conduce a bucles infinitos en los sistemas de producción que ejecutan software popular. El código en la pregunta realmente usa dos bloqueos para el mapa, que está por encima (aunque necesitaría una retención explícita del mismo bloqueo si usa un iterador). Al no ser final impide que la clase contenedora sea segura para la publicación no segura. Si map fue volatile y creó un nuevo mapa para cada put, entonces podría hacerse seguro sin sincronización en el get.

+0

Estoy usando Collections.synchronizedMap. ¿También es peligroso? Estoy haciendo modificaciones estructurales solo en mis setters. Así que sincronizo estos métodos, pero mis captadores solo obtienen los datos. ¿Debería sincronizarlos también? Me temo que mientras estoy estableciendo un valor en HashMap, a otro hilo le gustaría obtener el valor, y obtiene algo más que el valor anterior o el nuevo. – Bob

+0

'Collections.synchronizedMap' agrega sincronización, como su nombre indica, por lo que no es necesario. Puede obtener una mejor idea de lo que hace si inserta su código en el suyo y utiliza el 'HashMap' directamente. –

6

En lugar de ajustar su HashMap en algo para sincronizarlo, considere usar un java.util.concurrency.ConcurrentHashMap en su lugar.

Esta es una versión actualizada de HashMap que garantiza que "Las recuperaciones reflejan los resultados de las últimas operaciones de actualización completadas desde su inicio".

3

Las respuestas anteriores son correctas al señalar que con las nuevas (1.5+) JVM, la versión de Cadena es segura, con respecto a la corrupción de datos. Y parece ser consciente de un acceso no sincronizado a la baja; el de los cambios no necesariamente visibles a través de getters.

Sin embargo, la pregunta más útil es esta: ¿hay alguna razón para la sincronización aquí? Si esto es solo por estar interesado en saber esto, está todo bien. Pero para el código real, la regla general de las lecturas y escrituras es que si puede haber ambas, ambas deben estar sincronizadas. Entonces, aunque en este caso puede omitir la sincronización (lo que puede significar que los hilos no ven los cambios que hacen otros hilos), parece que hay poco beneficio al hacerlo.

+0

Mi aplicación es una aplicación de "motor de blogs". Guardo la primera X (digamos 10) de las entrys recién creadas en una variable. No es un problema que los usuarios no obtengan la versión actualizada de los entrys, ya que podrían actualizar la página si quisieran. Realizo cerca de 20 entrys en un día (setter), pero tengo cientos de miles de visitantes por día. No es eficiente (creo) sincronizar los métodos getter (tengo muchos métodos getter como el anterior). (No, aún no recibo cientos de miles de visitantes por día, pero quiero que mi aplicación pueda manejarlo) – Bob

+5

Tenga en cuenta que no se trata solo de que el usuario actualice la página. En el modelo de memoria Java, si no hay sincronización entre el hilo del colocador y el del captador, es posible que el hilo captador * nunca * obtenga el valor actualizado. Esto suena como una cosa de tipo de optimización prematura para mí. Hazlo correcto primero. Si más adelante ve que la sincronización realmente está limitando su rendimiento, puede buscar mejores formas de manejarlo. –

+0

"es posible que el hilo captador nunca obtenga el valor actualizado". ¿Cómo? Simplemente no entiendo. "35 seg 300 milisegundos" Obtengo el valor, es el anterior. "35 sec 500 milisegundos" Establecí el valor, que "50 segundos xxx milisegundos" ¿Trato de obtener el nuevo? ¿Cómo es posible que no obtenga el nuevo valor? – Bob

1

En el entorno de subprocesos múltiples deberá sincronizar el captador para garantizar que el cliente vea el valor más actualizado de s.

+0

haciendo que la variable "volátil" sea igual de efectiva y no requiera la sobrecarga de sincronización –

+2

'volátil' tiene su propia sobrecarga de sincronización incorporada. – Bombe

2

Quizás un Read Write Lock podría resolver su problema?

Tome un vistazo a su documentación:

bloqueo

Una lectura-escritura permite un mayor nivel de concurrencia en el acceso a los datos compartidos que el permitido por un bloqueo de exclusión mutua. Explota el hecho de que si bien solo un hilo a la vez (un hilo de escritor) puede modificar los datos compartidos, en muchos casos cualquier número de hilos puede leer simultáneamente los datos (de ahí los hilos del lector). En teoría, el aumento de concurrencia permitido por el uso de un bloqueo de lectura y escritura dará lugar a mejoras en el rendimiento sobre el uso de un bloqueo de exclusión mutua. ....

+0

+1 pero me sorprendería que las colecciones sincronizadas no lo usen todavía. – HRJ