Solución:
Intentaré agregar un ejemplo para aclararlo aún más.
Como se ha mencionado, sincronizado en Java es una implementación del concepto Monitor. Cuando marca un bloque de código como sincronizado, usa un objeto como parámetro. Cuando un subproceso en ejecución llega a dicho bloque de código, primero debe esperar hasta que no haya otro subproceso en ejecución en un bloque sincronizado en ese mismo objeto.
Object a = new Object();
Object b = new Object();
...
synchronized(a){
doStuff();
}
...
synchronized(b){
doSomeStuff();
}
...
synchronized(a){
doOtherStuff();
}
En el ejemplo anterior, un hilo que se ejecuta doOtherStuff()
bloquearía otro hilo para que no entre en el bloque de protección de código doStuff()
. Sin embargo, un hilo podría entrar al bloque alrededor doSomeStuff()
sin problema ya que está sincronizado en Object b
, no Object a
.
Cuando usa el modificador sincronizado en un método de instancia (un método no estático), es muy similar a tener un bloque sincronizado con “this” como argumento. Entonces, en el siguiente ejemplo, methodA()
y methodB()
actuará de la misma manera:
public synchronized void methodA() {
doStuff();
}
...
public void methodB() {
synchronized(this) {
doStuff();
}
}
Tenga en cuenta que si tiene un methodC()
en esa clase que no está sincronizada y no tiene un bloque sincronizado, nada impedirá que un hilo ingrese a ese método y la programación descuidada podría permitir que ese hilo acceda a código no seguro en el objeto.
Si tienes un método estático con el modificador sincronizado, es prácticamente lo mismo que tener un bloque sincronizado con ClassName.class
como argumento (si tiene un objeto de esa clase, ClassName cn = new ClassName();
, puede acceder a ese objeto con Class c = cn.getClass();
)
class ClassName {
public void static synchronized staticMethodA() {
doStaticStuff();
}
public static void staticMethodB() {
synchronized(ClassName.class) {
doStaticStuff();
}
}
public void nonStaticMethodC() {
synchronized(this.getClass()) {
doStuff();
}
}
public static void unSafeStaticMethodD() {
doStaticStuff();
}
}
Entonces, en el ejemplo anterior, staticMethodA()
y staticMethodB()
actuar de la misma manera. Un hilo en ejecución también será bloqueado para acceder al bloque de código en nonStaticMethodC()
ya que se sincroniza en el mismo objeto.
Sin embargo, es importante saber que nada impedirá que un hilo en ejecución acceda unSafeStaticMethodD()
. Incluso si decimos que un método estático “se sincroniza en el objeto Clase”, no significa que sincroniza todos los accesos a los métodos de esa clase. Simplemente significa que usa el objeto Class para sincronizar. Aún es posible el acceso no seguro.
En resumen, si sincroniza en un método estático, sincronizará en la clase (objeto) y no en una instancia (objeto). Eso significa que mientras la ejecución de un método estático, toda la clase está bloqueada. Por tanto, también se bloquean otros métodos sincronizados estáticos.
La sincronización en Java es básicamente una implementación de monitores. Al sincronizar un método no estático, el monitor pertenece a la instancia. Al sincronizar en un método estático, el monitor pertenece a la clase. Sincronizar un bloque de código es la misma idea, pero el monitor pertenece al objeto especificado. Si puede salirse con la suya, los bloques sincronizados son preferibles porque minimizan el tiempo que cada hilo pasa en la sección crítica