2008-09-23 7 views
9

Cuando se accede a un campo de clase mediante un método getter por varios subprocesos, ¿cómo se mantiene la seguridad de subprocesos? ¿Es suficiente la palabra clave sincronizada?¿Cómo se asegura de que varios hilos puedan acceder de forma segura a un campo de clase?

Es esto seguro:

public class SomeClass { 
    private int val; 

    public synchronized int getVal() { 
     return val; 
    } 

    private void setVal(int val) { 
     this.val = val; 
    } 
} 

o sí introduce la incubadora más complicaciones?

+0

tl; dr: esto no es seguro para subprocesos. –

Respuesta

17

Si usa 'sincronizado' en el setter aquí también, este código es seguro para la rosca. Sin embargo, puede no ser suficientemente granular; si tiene 20 getters y setters y todos están sincronizados, puede estar creando un cuello de botella de sincronización. En esta instancia específica, con una sola variable int, eliminar el 'sincronizado' y marcar el campo int 'volátil' también asegurará la visibilidad (cada thread verá el último valor de 'val' al llamar al getter) pero puede no estar sincronizado lo suficiente para sus necesidades. Por ejemplo, esperando

int old = someThing.getVal(); 
if (old == 1) { 
    someThing.setVal(2); 
} 

para establecer val en 2 si y solo si ya es 1 incorrecto. Para esto necesita un bloqueo externo, o algún método atómico de comparación y configuración.

sugiero que lea Java concurrencia en la práctica por Brian Goetz et al , que tiene la mejor cobertura de las construcciones de concurrencia de Java.

+0

Consulte mi respuesta para obtener una forma adicional de hacer una comparación y almacenar –

2

Según mi entender, debe utilizar sincronizado en los métodos getter y setter, y eso es suficiente.

Editar: Aquí hay un link para obtener más información sobre la sincronización y qué no.

-3

La sincronización existe para proteger contra la interferencia de hilo y los errores de consistencia de la memoria. Al sincronizar en getVal(), el código garantiza que otros métodos sincronizados en SomeClass no se ejecuten al mismo tiempo. Como no hay otros métodos sincronizados, no proporciona mucho valor. También tenga en cuenta que las lecturas y escrituras en primitivos tienen acceso atómico. Eso significa que con una programación cuidadosa, no es necesario sincronizar el acceso al campo.

Lea Sychronization.

No estoy seguro de por qué esto se redujo a -3. Simplemente estoy resumiendo lo que dice el tutorial de Sincronización de Sun (así como también mi propia experiencia).

El uso sencillo acceso a variables atómica es más eficiente que el acceso a estos las variables a través de código sincronizado, pero requiere más cuidado por la programador para evitar la consistencia de memoria errores. Si el esfuerzo adicional es vale la pena depende del tamaño y complejidad de la aplicación.

+0

"las lecturas y escrituras en primitivos tienen acceso atómico" - no es así. Las lecturas y escrituras en largos y dobles son solo atómicas si están marcadas como volátiles. –

+0

Oh, sí, y la garantía solo se aplica a las variables, no a los elementos en una matriz de tipo primitivo. –

+0

Lee y escribe en un campo (con las advertencias ya indicadas) son atómicas pero no son suficientes para garantizar la publicación. Por lo tanto, escribir en un campo int se escribirá con seguridad en el campo, pero NO HAY GARANTÍA de que otros hilos verán la escritura. A menos que use sincronizado o volátil. –

3

Además de Cowan's comment, se puede hacer lo siguiente para una comparación y de guardar:

synchronized(someThing) { 
    int old = someThing.getVal(); 
    if (old == 1) { 
     someThing.setVal(2); 
    } 
} 

Esto funciona porque la cerradura definida a través de un método sincronizado es implícitamente el mismo que el bloqueo del objeto (see java language spec) .

+0

pero depende completamente de la concordancia de concurrencia del código del cliente - no es aconsejable (-1) – xtofl

0

Para objetos simples, esto puede ser suficiente. En la mayoría de los casos, debe evitar la palabra clave sincronizada porque puede encontrarse con un punto muerto de sincronización.

Ejemplo:

asegura que sólo un hilo lee o escribe en el miembro de instancia local.

leído el libro "Programación Concurrente en Java (TM): Principios y patrones de diseño (Java (Addison-Wesley))", tal vez http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html es también útil ...

1

Si su clase contiene una sola variable, entonces otra forma de lograr seguridad de hilos es usar el objeto AtomicInteger existente.

public class ThreadSafeSomeClass { 

    private final AtomicInteger value = new AtomicInteger(0); 

    public void setValue(int x){ 
     value.set(x); 
    } 

    public int getValue(){ 
     return value.get(); 
    } 

} 

Sin embargo, si se agrega variables adicionales tales que son dependientes (estado de una variable depende del estado de otro), entonces AtomicInteger no funcionará.

Haciendo eco de la sugerencia de leer "Concurrencia de Java en la práctica".

+0

Estás matando a una hormiga con un martillo. Este es un caso de uso muy pobre para AtomicInteger. Simplemente marque el campo 'value'' volátil' y obtendrá un código equivalente. –

Cuestiones relacionadas