threads thread sincronizacion resueltos programar pildorasinformaticas pildoras informaticas hilos ejemplos curso clase java multithreading synchronized

java - thread - ¿Cómo se asegura de que varios hilos puedan acceder de forma segura a un campo de clase?



programar hilos (6)

Desde mi punto de vista, debes usar sincronización en los métodos getter y setter, y eso es suficiente.

Editar: Aquí hay un enlace a más información sobre sincronización y qué no.

Cuando se accede a un campo de clase a través de un método getter por varios subprocesos, ¿cómo se mantiene la seguridad de subprocesos? ¿Es suficiente la palabra clave sincronizada?

Es esto seguro?

public class SomeClass { private int val; public synchronized int getVal() { return val; } private void setVal(int val) { this.val = val; } }

o el setter introduce complicaciones adicionales?


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.

Lee la sincronización .

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 de acceso variable atómico simple es más eficiente que acceder a estas variables a través del código sincronizado, pero requiere más cuidado por parte del programador para evitar errores de consistencia de la memoria. Si el esfuerzo adicional vale la pena depende del tamaño y la complejidad de la aplicación.


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:

public class SomeClass { private Object mutex = new Object(); private int val = -1; // TODO: Adjust initialization to a reasonable start // value public int getVal() { synchronized ( mutex ) { return val; } } private void setVal( int val ) { synchronized ( mutex ) { this.val = val; } } }

Asegura que solo un hilo lee o escribe en el miembro de la instancia local.

Lea 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 también es útil ...


Si usa ''synchronized'' en el setter aquí también, este código es threadsafe. 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 subproceso verá el último valor de ''val'' al llamar al captador) pero puede que 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 es incorrecto. Para esto necesita un bloqueo externo, o algún método atómico de comparación y configuración.

Le sugiero que lea Java Concurrency In Practice por Brian Goetz y otros , tiene la mejor cobertura de los constructos de simultaneidad de Java.


Si su clase contiene solo una 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 agrega variables adicionales tales que son dependientes (el estado de una variable depende del estado de otra), entonces AtomicInteger no funcionará.

Haciéndose eco de la sugerencia de leer "Concurrencia de Java en la práctica".


Además del comentario de Cowan , podría hacer lo siguiente para comparar y almacenar:

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

Esto funciona porque el bloqueo definido mediante un método sincronizado es implícitamente el mismo que el bloqueo del objeto ( consulte la especificación del lenguaje Java ).