variable sirve sincronizar sincronizados que productores productor procesos para hilos fuente ejemplos consumidores consumidor codigo acceso java concurrency synchronization methods non-static

sirve - ¿Qué casos requieren acceso al método sincronizado en Java?



synchronized java netbeans (6)

¿En qué casos es necesario sincronizar el acceso a los miembros de la instancia? Entiendo que el acceso a miembros estáticos de una clase siempre debe estar sincronizado, ya que se comparten en todas las instancias de objeto de la clase.

Mi pregunta es cuándo sería incorrecto si no sincronizo los miembros de la instancia.

por ejemplo, si mi clase es

public class MyClass { private int instanceVar = 0; public setInstanceVar() { instanceVar++; } public getInstanceVar() { return instanceVar; } }

en qué casos (de uso de la clase MyClass ) necesitaría tener métodos: public synchronized setInstanceVar() public synchronized getInstanceVar() y public synchronized getInstanceVar() ?

Gracias de antemano por sus respuestas.


. Aproximadamente, la respuesta es "depende". La sincronización de su setter y getter aquí solo tiene el propósito de garantizar que los threads múltiples no puedan leer las variables entre las operaciones incrementales de los demás:

synchronized increment() { i++ } synchronized get() { return i; }

pero eso ni siquiera funcionaría aquí, porque para asegurarse de que el hilo de su llamador obtuviera el mismo valor que incrementó, tendría que garantizar que está aumentando atómicamente y luego recuperando, lo que no está haciendo aquí, es decir, usted Tendría que hacer algo como

synchronized int { increment return get() }

Básicamente, la sincronización es útil para definir qué operaciones deben garantizarse para ejecutar Threadsafe (en otras palabras, no puede crear una situación donde un hilo separado socava su operación y hace que su clase se comporte de forma ilógica, o socava lo que espera el estado de los datos ser). En realidad es un tema más grande que se puede abordar aquí.

Este libro Java Concurrency in Practice es excelente, y ciertamente mucho más confiable que yo.


Depende de si quieres que tu clase sea segura para subprocesos. La mayoría de las clases no deben ser seguras para subprocesos (por simplicidad) en cuyo caso no necesita sincronización. Si necesita que sea seguro para subprocesos, debe sincronizar el acceso o hacer que la variable sea volátil. (Evita que otros hilos obtengan datos "obsoletos").


El modificador synchronized es realmente una mala idea y debe evitarse a toda costa. Creo que es encomiable que Sun haya tratado de hacer que el bloqueo sea un poco más fácil de lograr, pero la synchronized solo causa más problemas de lo que vale.

El problema es que un método synchronized es en realidad solo azúcar de sintaxis para obtener el bloqueo y mantenerlo durante todo el proceso. Por lo tanto, public synchronized void setInstanceVar() sería equivalente a algo como esto:

public void setInstanceVar() { synchronized(this) { instanceVar++; } }

Esto es malo por dos razones:

  • Todos synchronized métodos synchronized dentro de la misma clase usan el mismo bloqueo exacto, lo que reduce el rendimiento
  • Cualquiera puede obtener acceso a la cerradura, incluidos los miembros de otras clases.

No hay nada que me impida hacer algo como esto en otra clase:

MyClass c = new MyClass(); synchronized(c) { ... }

Dentro de ese bloque synchronized , estoy manteniendo el bloqueo requerido por todos synchronized métodos synchronized dentro de MyClass . Esto reduce aún más el rendimiento y aumenta drásticamente las posibilidades de un punto muerto.

Un mejor enfoque es tener un objeto de lock dedicado y usar el bloque synchronized(...) directamente:

public class MyClass { private int instanceVar; private final Object lock = new Object(); // must be final! public void setInstanceVar() { synchronized(lock) { instanceVar++; } } }

Alternativamente, puede usar la interfaz java.util.concurrent.Lock y la implementación java.util.concurrent.locks.ReentrantLock para lograr básicamente el mismo resultado (de hecho, es lo mismo en Java 6).


En Java, las operaciones en ints son atómicas, por lo que no, en este caso no necesita sincronizar si todo lo que hace es 1 escritura y 1 lectura a la vez.

Si estos fueron largos o dobles, necesita sincronizarse porque es posible que parte del largo / doble se actualice, luego se lee otro hilo, y finalmente se actualiza la otra parte del largo / doble.


Para decirlo simplemente, usa sincronizado cuando tiene subprocesos múltiples que acceden al mismo método de la misma instancia que cambiará el estado del objeto / aplicación.

Se trata de una forma simple de evitar condiciones de carrera entre subprocesos, y en realidad solo debería usarlo cuando esté planeando tener subprocesos simultáneos que accedan a la misma instancia, como un objeto global.

Ahora, cuando está leyendo el estado de una instancia de un objeto con subprocesos concurrentes, es posible que desee buscar en el java.util.concurrent.locks.ReentrantReadWriteLock, que en teoría permite que muchos subprocesos puedan leer a la vez, pero solo un hilo tiene permiso para escribir. Por lo tanto, en el ejemplo del método getter y setting que todo el mundo parece estar dando, puede hacer lo siguiente:

public class MyClass{ private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private int myValue = 0; public void setValue(){ rwl.writeLock().lock(); myValue++; rwl.writeLock().unlock(); } public int getValue(){ rwl.readLock.lock(); int result = myValue; rwl.readLock.unlock(); return result; } }


Si desea que esta clase sea segura, declararía instanceVar como volatile para asegurarme de obtener siempre el valor más actualizado de la memoria y también haría que setInstanceVar() synchronized porque en la JVM un incremento no es una operación atómica.

private volatile int instanceVar =0; public synchronized setInstanceVar() { instanceVar++; }